att
This commit is contained in:
parent
eaf0ed70a7
commit
4aa75efedc
589
estoque_mar.py
Normal file
589
estoque_mar.py
Normal file
@ -0,0 +1,589 @@
|
||||
import requests
|
||||
import json
|
||||
import time
|
||||
import os
|
||||
import pandas as pd
|
||||
import pyodbc
|
||||
import warnings
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
# Suprimir avisos do openpyxl
|
||||
warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl')
|
||||
|
||||
# Configurações
|
||||
DIRETORIO_TEMP = "/tmp/download"
|
||||
|
||||
# Lista de colunas na ordem exata do banco
|
||||
COLUNAS_BANCO = [
|
||||
'SKU', 'SKU_PARA', 'DESCRICAO', 'CATEGORIA', 'CLASSE',
|
||||
'FASES PRODUTO', 'LANCAMENTO', 'DESATIVACAO', 'PDV',
|
||||
'ESTOQUE ATUAL', 'ESTOQUE EM TRANSITO', 'PEDIDO PENDENTE',
|
||||
'COBERTURA ALVO', 'ESTOQUE DE SEGURANCA', 'DDV PREVISTO',
|
||||
'COBERTURA ATUAL', 'COBERTURA ATUAL + TRANSITO',
|
||||
'COBERTURA PROJETADA', 'ORIGEM', 'loja_id'
|
||||
]
|
||||
|
||||
# Headers comuns para as requisições
|
||||
HEADERS_API = {
|
||||
"accept": "*/*",
|
||||
"accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
|
||||
"authorization": "Basic b2NVc2VySW50ZXJuYWw6Nk5RV0BOU2M1anpEUy1oeg==",
|
||||
"content-type": "application/json",
|
||||
"origin": "https://extranet.grupoboticario.com.br",
|
||||
"priority": "u=1, i",
|
||||
"referer": "https://extranet.grupoboticario.com.br/",
|
||||
"sec-ch-ua": '"Google Chrome";v="137", "Chromium";v="137", "Not/A)Brand";v="24"',
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": '"Windows"',
|
||||
"sec-fetch-dest": "empty",
|
||||
"sec-fetch-mode": "cors",
|
||||
"sec-fetch-site": "cross-site",
|
||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
|
||||
"x-authorization": "Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InV6YkJManZabTJxVDRsSERBZXdBX3Ewd2ZscTQtVGJnZmhVUzBBUE5HVzQiLCJ0eXAiOiJKV1QifQ.eyJhdWQiOiJhNmNkNGZlNi0zZDcxLTQ1NWEtYjk5ZC1mNDU4YTA3Y2MwZDEiLCJpc3MiOiJodHRwczovL2xvZ2luLmV4dHJhbmV0LmdydXBvYm90aWNhcmlvLmNvbS5ici8xZTYzOTJiZC01Mzc3LTQ4ZjAtOWE4ZS00NjdmNWIzODFiMTgvdjIuMC8iLCJleHAiOjE3NTAyNjg5NjAsIm5iZiI6MTc1MDI2NTM2MCwic3ViIjoiNTI0MDliZmYtODNlNC00MjliLThmNGEtYzdjMDc2MGZiMmNlIiwiZW1haWwiOiJkYW5pZWwucm9kcmlndWVAZS1ib3RpY2FyaW8uY29tLmJyIiwibmFtZSI6IkRhbmllbCBKb3NlIE1lZGVpcm9zIFJvZHJpZ3VlcyIsImdpdmVuX25hbWUiOiJEYW5pZWwiLCJmYW1pbHlfbmFtZSI6IlJvZHJpZ3VlcyIsImV4dGVuc2lvbl9DUEYiOiIxMTExMzE3NDQ1NSIsInN0b3JlcyI6WyI0NDk0Il0sInJvbGVzIjpbIkNSRURfQURNIiwiR0NfTEVJVFVSQSIsIkxJVkVTX0ZEViIsIk1BUl9GUkFOUVVFQURPX0FETUlOIiwiUEJfQURNX1BBR0FET1IiLCJQR0lfUkVTVUxUQURPX1BEViIsIlZESV9TVUYiXSwiY3AiOiIxMDI2OSIsInJlZ2lzdHJhdGlvbiI6Ijg2MDk4NDAwIiwibGlueG9tcyI6ImNvbGFib3JhZG9yIiwiZW1haWxfdmVyaWZpZWQiOiJ0cnVlIiwic2NwIjoiZXh0cmFuZXQuYXBpIiwiYXpwIjoiYjMwMDFlNjAtYThlMC00ZGE4LTgyYmEtYzNhNzAxNDA1ZjA4IiwidmVyIjoiMS4wIiwiaWF0IjoxNzUwMjY1MzYwfQ.klcrMK2sx7GEJlMx_dbwgopc1RFjJwBLh0kLqjLlk__POtHNpJKti42r6xSuAM5AnieVMx0koK2oyg3eGoQJEchttsr4LyVoqSpcKzrqTR69gEHbTMo-EWWh_UglM6tr7ge6dzMF4yg-R_2XHwlrNEoYthVEVnSF1cqBxCHdTlRJcmso0q3ObGUU4heA-55OkzBjZ2Nz1mL7MmujZmNHlQXsoQ2vtOnnM3Ui7SAy08jGsIAIHdH8UKy0Xg-GrzjVrUwqAmyadSpXnvLc1sAE--bbtxP-3ADmnvHdxffkfQFtbPC0lws0MgESaqrIn0I9X6_OkAnUuMA_cCD9QJoyTA",
|
||||
"x-correlation-id": "15508cc3-fa35-47bf-ab19-8361f870e197",
|
||||
"x-user-id": "163165",
|
||||
"x-username": "daniel.rodrigue"
|
||||
}
|
||||
|
||||
# Configurações dos dois grupos de lojas
|
||||
LOJAS_GRUPO_1 = [
|
||||
"24268", "24258", "23701", "23702", "23705", "23706", "23665", "23709", "23708",
|
||||
"23713", "23707", "23156", "24254", "24253", "23813", "20056", "23475", "3546",
|
||||
"21647", "12824", "14617", "4560", "21068", "21277", "21296", "21381", "13427",
|
||||
"21624", "19103", "14668", "20006", "20057", "20005", "20009", "5699",
|
||||
"12522", "12817", "12820", "12829", "12818", "12823", "12826", "12828",
|
||||
"12830", "12838", "20441", "20858", "21007", "910173", "910291"
|
||||
]
|
||||
|
||||
LOJAS_GRUPO_2 = [
|
||||
"20992", "21383", "23704", "23703", "20986", "24293", "23712", "20994", "23711",
|
||||
"24269", "21000", "21001", "21375", "20970", "20989", "22541", "20988", "20993",
|
||||
"20999", "24255", "24257", "20991", "20969", "20998", "20996", "20997", "20995",
|
||||
"21495", "20968", "21278"
|
||||
]
|
||||
|
||||
|
||||
def criar_diretorio_temp():
|
||||
"""Cria o diretório temporário se não existir."""
|
||||
os.makedirs(DIRETORIO_TEMP, exist_ok=True)
|
||||
print(f"✓ Diretório temporário criado/verificado: {DIRETORIO_TEMP}")
|
||||
|
||||
|
||||
def fazer_requisicao_stock(store_codes, nome_grupo):
|
||||
"""
|
||||
Faz uma requisição para a API de exportação de stock.
|
||||
|
||||
Args:
|
||||
store_codes: Lista de códigos de lojas
|
||||
nome_grupo: Nome do grupo para identificação
|
||||
|
||||
Returns:
|
||||
dict: Response da API ou None se erro
|
||||
"""
|
||||
url = "https://mar-orders-bff-api.demanda-abastecimento.grupoboticario.digital/api/export/STOCK"
|
||||
|
||||
payload = {
|
||||
"storeCodes": store_codes,
|
||||
"cpId": 10269,
|
||||
"fileType": "XLSX",
|
||||
"userId": "163165",
|
||||
"metadata": {
|
||||
"storeCodes": store_codes,
|
||||
"userName": "Daniel Jose Medeiros Rodrigues",
|
||||
"fileFormattedName": f"Consulta de estoque {nome_grupo}.XLSX",
|
||||
"create_at": datetime.now(timezone.utc).isoformat(),
|
||||
"exportType": "STOCK"
|
||||
},
|
||||
"validateOnRequest": True
|
||||
}
|
||||
|
||||
try:
|
||||
print(f" Fazendo requisição para {nome_grupo}...")
|
||||
response = requests.post(url, headers=HEADERS_API, json=payload)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
print(f" ✗ Erro na requisição para {nome_grupo}: {e}")
|
||||
return None
|
||||
except json.JSONDecodeError as e:
|
||||
print(f" ✗ Erro ao decodificar JSON para {nome_grupo}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def tentar_download(request_id):
|
||||
"""
|
||||
Tenta fazer o download da exportação usando o requestId.
|
||||
|
||||
Args:
|
||||
request_id: ID da requisição
|
||||
|
||||
Returns:
|
||||
dict: Resultado da API de download ou None se erro
|
||||
"""
|
||||
url = f"https://mar-orders-bff-api.demanda-abastecimento.grupoboticario.digital/api/export/{request_id}/download"
|
||||
params = {"redirect": "false"}
|
||||
|
||||
try:
|
||||
response = requests.get(url, headers=HEADERS_API, params=params)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def aguardar_download_disponivel(request_id, nome_grupo, timeout_minutes=90):
|
||||
"""
|
||||
Aguarda até que o download esteja disponível.
|
||||
|
||||
Args:
|
||||
request_id: ID da requisição para aguardar
|
||||
nome_grupo: Nome do grupo para identificação
|
||||
timeout_minutes: Tempo limite em minutos (padrão: 90 min)
|
||||
|
||||
Returns:
|
||||
dict: Resultado final com URL de download ou None se erro/timeout
|
||||
"""
|
||||
print(f" Aguardando download de {nome_grupo} (ID: {request_id})...")
|
||||
|
||||
timeout_seconds = timeout_minutes * 60
|
||||
start_time = time.time()
|
||||
tentativas = 0
|
||||
|
||||
while True:
|
||||
elapsed_time = time.time() - start_time
|
||||
if elapsed_time > timeout_seconds:
|
||||
print(f" ✗ Timeout atingido para {nome_grupo} ({timeout_minutes} minutos)")
|
||||
return None
|
||||
|
||||
tentativas += 1
|
||||
resultado_download = tentar_download(request_id)
|
||||
|
||||
if resultado_download and 'fileUrl' in resultado_download:
|
||||
print(f" ✓ Download de {nome_grupo} disponível após {tentativas} tentativas!")
|
||||
return resultado_download
|
||||
|
||||
if tentativas % 6 == 0: # Log a cada minuto (6 tentativas de 10s)
|
||||
print(f" ... Aguardando {nome_grupo} ({tentativas} tentativas, {int(elapsed_time)}s)")
|
||||
|
||||
time.sleep(10)
|
||||
|
||||
|
||||
def baixar_e_salvar_arquivo(file_url, nome_arquivo):
|
||||
"""
|
||||
Baixa o arquivo da URL fornecida e salva no diretório temporário.
|
||||
|
||||
Args:
|
||||
file_url: URL do arquivo para download
|
||||
nome_arquivo: Nome do arquivo a ser salvo
|
||||
|
||||
Returns:
|
||||
str: Caminho completo do arquivo salvo ou None se erro
|
||||
"""
|
||||
try:
|
||||
caminho_completo = os.path.join(DIRETORIO_TEMP, nome_arquivo)
|
||||
print(f" Baixando {nome_arquivo}...")
|
||||
|
||||
response = requests.get(file_url, stream=True)
|
||||
response.raise_for_status()
|
||||
|
||||
with open(caminho_completo, 'wb') as arquivo:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
if chunk:
|
||||
arquivo.write(chunk)
|
||||
|
||||
if os.path.exists(caminho_completo) and os.path.getsize(caminho_completo) > 0:
|
||||
tamanho_mb = os.path.getsize(caminho_completo) / (1024 * 1024)
|
||||
print(f" ✓ Arquivo baixado: {nome_arquivo} ({tamanho_mb:.2f} MB)")
|
||||
return caminho_completo
|
||||
else:
|
||||
print(f" ✗ Erro: Arquivo não foi salvo corretamente")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f" ✗ Erro ao baixar arquivo: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def enviar_status_api(status_id, status="OK"):
|
||||
"""
|
||||
Envia o status da execução para a API.
|
||||
|
||||
Args:
|
||||
status_id: ID do status (2 para grupo 1, 5 para grupo 2)
|
||||
status: Status a ser enviado, "OK" ou "FAIL"
|
||||
"""
|
||||
url = f"https://api.grupoginseng.com.br/api/status/{status_id}"
|
||||
sao_paulo_offset = timedelta(hours=-3)
|
||||
current_datetime = datetime.now(timezone(sao_paulo_offset)).strftime("%Y-%m-%d %H:%M:%S")
|
||||
|
||||
payload = {"STATUS": status, "DATA": current_datetime}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
try:
|
||||
response = requests.put(url, json=payload, headers=headers)
|
||||
print(f" Status enviado para API (ID {status_id}): {status} - {response.status_code}")
|
||||
except Exception as e:
|
||||
print(f" ✗ Erro ao enviar status: {e}")
|
||||
|
||||
|
||||
def processar_download_grupo(store_codes, nome_grupo, nome_arquivo, status_id):
|
||||
"""
|
||||
Processa o download de um grupo de lojas.
|
||||
|
||||
Args:
|
||||
store_codes: Lista de códigos de lojas
|
||||
nome_grupo: Nome do grupo para identificação
|
||||
nome_arquivo: Nome do arquivo a ser salvo
|
||||
status_id: ID do status para enviar à API
|
||||
|
||||
Returns:
|
||||
str: Caminho do arquivo baixado ou None se erro
|
||||
"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"PROCESSANDO {nome_grupo}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
# 1. Fazer requisição inicial
|
||||
resultado_inicial = fazer_requisicao_stock(store_codes, nome_grupo)
|
||||
if not resultado_inicial:
|
||||
enviar_status_api(status_id, "FAIL")
|
||||
return None
|
||||
|
||||
request_id = resultado_inicial.get('id') or resultado_inicial.get('requestId')
|
||||
if not request_id:
|
||||
print(f" ✗ ID da requisição não encontrado para {nome_grupo}")
|
||||
enviar_status_api(status_id, "FAIL")
|
||||
return None
|
||||
|
||||
print(f" ✓ Requisição iniciada - ID: {request_id}")
|
||||
|
||||
# 2. Aguardar download ficar disponível
|
||||
resultado_download = aguardar_download_disponivel(request_id, nome_grupo)
|
||||
if not resultado_download:
|
||||
enviar_status_api(status_id, "FAIL")
|
||||
return None
|
||||
|
||||
file_url = resultado_download.get('fileUrl', '')
|
||||
if not file_url:
|
||||
print(f" ✗ URL do arquivo não encontrada para {nome_grupo}")
|
||||
enviar_status_api(status_id, "FAIL")
|
||||
return None
|
||||
|
||||
# 3. Baixar arquivo
|
||||
arquivo_salvo = baixar_e_salvar_arquivo(file_url, nome_arquivo)
|
||||
if arquivo_salvo:
|
||||
enviar_status_api(status_id, "OK")
|
||||
return arquivo_salvo
|
||||
else:
|
||||
enviar_status_api(status_id, "FAIL")
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# FUNÇÕES DE UPLOAD PARA O BANCO DE DADOS
|
||||
# ============================================================================
|
||||
|
||||
def conectar_banco():
|
||||
"""Estabelece conexão com o banco de dados."""
|
||||
try:
|
||||
conn = pyodbc.connect(
|
||||
'DRIVER={ODBC Driver 18 for SQL Server};'
|
||||
'SERVER=10.77.77.10;'
|
||||
'DATABASE=GINSENG;'
|
||||
'UID=supginseng;'
|
||||
'PWD=Iphone2513@;'
|
||||
'PORT=1433;'
|
||||
'TrustServerCertificate=yes'
|
||||
)
|
||||
return conn
|
||||
except Exception as e:
|
||||
print(f"✗ Erro ao conectar ao banco de dados: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def limpar_tabela(conn):
|
||||
"""Limpa a tabela estoque_mar."""
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
print(" Limpando tabela estoque_mar...")
|
||||
cursor.execute("DELETE FROM [GINSENG].[dbo].[estoque_mar]")
|
||||
conn.commit()
|
||||
print(" ✓ Tabela limpa com sucesso!")
|
||||
except Exception as e:
|
||||
print(f" ✗ Erro ao limpar tabela: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def unificar_arquivo(caminho_arquivo):
|
||||
"""Unifica as três páginas (BOT, EUD, QDB) de um arquivo Excel."""
|
||||
try:
|
||||
# Lê cada página do arquivo
|
||||
df_bot = pd.read_excel(caminho_arquivo, sheet_name='BOT')
|
||||
df_eud = pd.read_excel(caminho_arquivo, sheet_name='EUD')
|
||||
df_qdb = pd.read_excel(caminho_arquivo, sheet_name='QDB')
|
||||
|
||||
# Adiciona coluna de origem
|
||||
df_bot['ORIGEM'] = 'BOT'
|
||||
df_eud['ORIGEM'] = 'EUD'
|
||||
df_qdb['ORIGEM'] = 'QDB'
|
||||
|
||||
# Concatena os DataFrames
|
||||
df_unificado = pd.concat([df_bot, df_eud, df_qdb], ignore_index=True)
|
||||
|
||||
# Garante que todas as colunas necessárias existem
|
||||
for coluna in COLUNAS_BANCO:
|
||||
if coluna not in df_unificado.columns:
|
||||
df_unificado[coluna] = None
|
||||
|
||||
# Define loja_id como igual ao PDV
|
||||
df_unificado['loja_id'] = df_unificado['PDV']
|
||||
|
||||
# Reordena as colunas na ordem correta do banco
|
||||
df_unificado = df_unificado[COLUNAS_BANCO]
|
||||
|
||||
return df_unificado
|
||||
|
||||
except Exception as e:
|
||||
print(f" ✗ Erro ao unificar arquivo {caminho_arquivo}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def formatar_data(valor):
|
||||
"""Formata uma data no formato YYYYMM."""
|
||||
try:
|
||||
if pd.isna(valor) or valor == '-':
|
||||
return None
|
||||
data_str = str(int(float(valor)))
|
||||
if len(data_str) >= 6:
|
||||
return data_str[:6]
|
||||
return None
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def formatar_numero(valor, max_length=50):
|
||||
"""Formata um número como string, usando vírgula como separador decimal."""
|
||||
try:
|
||||
if pd.isna(valor) or valor == '-':
|
||||
return None
|
||||
num = float(str(valor).replace(',', '.'))
|
||||
if num.is_integer():
|
||||
return str(int(num))[:max_length]
|
||||
return f"{num:.2f}".replace('.', ',')[:max_length]
|
||||
except:
|
||||
return None
|
||||
|
||||
|
||||
def enviar_para_banco(conn, df):
|
||||
"""Envia os dados do DataFrame para o banco."""
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
total_linhas = len(df)
|
||||
linhas_processadas = 0
|
||||
erros = 0
|
||||
|
||||
for _, row in df.iterrows():
|
||||
try:
|
||||
valores = []
|
||||
for coluna in COLUNAS_BANCO:
|
||||
valor = row[coluna]
|
||||
|
||||
if pd.isna(valor) or valor == '-':
|
||||
valores.append(None)
|
||||
elif coluna in ['SKU', 'PDV', 'loja_id']:
|
||||
valores.append(str(int(float(valor)))[:50])
|
||||
elif coluna in ['LANCAMENTO', 'DESATIVACAO']:
|
||||
valores.append(formatar_data(valor))
|
||||
elif coluna in ['ESTOQUE ATUAL', 'ESTOQUE EM TRANSITO', 'PEDIDO PENDENTE',
|
||||
'COBERTURA ALVO', 'ESTOQUE DE SEGURANCA', 'DDV PREVISTO',
|
||||
'COBERTURA ATUAL', 'COBERTURA ATUAL + TRANSITO', 'COBERTURA PROJETADA']:
|
||||
valores.append(formatar_numero(valor))
|
||||
elif coluna == 'DESCRICAO':
|
||||
valores.append(str(valor)[:255] if pd.notna(valor) else None)
|
||||
elif coluna in ['CATEGORIA', 'CLASSE', 'FASES PRODUTO', 'ORIGEM']:
|
||||
valores.append(str(valor)[:100] if pd.notna(valor) else None)
|
||||
else:
|
||||
if isinstance(valor, (int, float)):
|
||||
valor = str(int(valor))
|
||||
valores.append(str(valor)[:50] if pd.notna(valor) else None)
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO [GINSENG].[dbo].[estoque_mar] (
|
||||
[SKU], [SKU_PARA], [DESCRICAO], [CATEGORIA], [CLASSE],
|
||||
[FASES PRODUTO], [LANCAMENTO], [DESATIVACAO], [PDV],
|
||||
[ESTOQUE ATUAL], [ESTOQUE EM TRANSITO], [PEDIDO PENDENTE],
|
||||
[COBERTURA ALVO], [ESTOQUE DE SEGURANCA], [DDV PREVISTO],
|
||||
[COBERTURA ATUAL], [COBERTURA ATUAL + TRANSITO],
|
||||
[COBERTURA PROJETADA], [ORIGEM], [loja_id]
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", valores)
|
||||
|
||||
linhas_processadas += 1
|
||||
if linhas_processadas % 5000 == 0:
|
||||
conn.commit()
|
||||
print(f" Progresso: {linhas_processadas}/{total_linhas} linhas inseridas")
|
||||
|
||||
except Exception as e:
|
||||
erros += 1
|
||||
if erros <= 3:
|
||||
print(f" ✗ Erro ao inserir linha: {e}")
|
||||
continue
|
||||
|
||||
conn.commit()
|
||||
print(f" ✓ Total de linhas processadas: {linhas_processadas}")
|
||||
if erros > 0:
|
||||
print(f" ⚠ Total de erros: {erros}")
|
||||
return linhas_processadas > 0
|
||||
|
||||
except Exception as e:
|
||||
print(f" ✗ Erro ao enviar dados para o banco: {e}")
|
||||
conn.rollback()
|
||||
return False
|
||||
|
||||
|
||||
def processar_upload_banco(arquivos):
|
||||
"""
|
||||
Processa o upload dos arquivos para o banco de dados.
|
||||
|
||||
Args:
|
||||
arquivos: Lista de caminhos dos arquivos a processar
|
||||
|
||||
Returns:
|
||||
bool: True se sucesso, False se erro
|
||||
"""
|
||||
print(f"\n{'='*60}")
|
||||
print("PROCESSANDO UPLOAD PARA O BANCO DE DADOS")
|
||||
print(f"{'='*60}")
|
||||
|
||||
try:
|
||||
# Conecta ao banco
|
||||
print(" Conectando ao banco de dados...")
|
||||
conn = conectar_banco()
|
||||
print(" ✓ Conectado ao banco de dados")
|
||||
|
||||
# Limpa a tabela
|
||||
limpar_tabela(conn)
|
||||
|
||||
# Processa cada arquivo
|
||||
arquivos_processados = 0
|
||||
for arquivo in arquivos:
|
||||
if not arquivo or not os.path.exists(arquivo):
|
||||
print(f" ⚠ Arquivo não encontrado: {arquivo}")
|
||||
continue
|
||||
|
||||
nome_arquivo = os.path.basename(arquivo)
|
||||
print(f"\n Processando arquivo: {nome_arquivo}")
|
||||
|
||||
# Unifica as páginas do arquivo
|
||||
df_unificado = unificar_arquivo(arquivo)
|
||||
if df_unificado is None:
|
||||
print(f" ✗ Falha ao unificar arquivo: {nome_arquivo}")
|
||||
continue
|
||||
|
||||
print(f" Total de linhas: {len(df_unificado)}")
|
||||
|
||||
# Envia para o banco
|
||||
if enviar_para_banco(conn, df_unificado):
|
||||
arquivos_processados += 1
|
||||
print(f" ✓ Arquivo enviado ao banco com sucesso: {nome_arquivo}")
|
||||
else:
|
||||
print(f" ✗ Falha ao enviar arquivo: {nome_arquivo}")
|
||||
|
||||
# Fecha a conexão
|
||||
conn.close()
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"✓ Upload finalizado: {arquivos_processados}/{len(arquivos)} arquivos processados")
|
||||
print(f"{'='*60}")
|
||||
|
||||
return arquivos_processados > 0
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Erro durante o upload: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def limpar_arquivos_temporarios():
|
||||
"""Remove os arquivos temporários baixados."""
|
||||
try:
|
||||
if os.path.exists(DIRETORIO_TEMP):
|
||||
for arquivo in os.listdir(DIRETORIO_TEMP):
|
||||
caminho = os.path.join(DIRETORIO_TEMP, arquivo)
|
||||
try:
|
||||
os.remove(caminho)
|
||||
print(f" ✓ Arquivo removido: {arquivo}")
|
||||
except Exception as e:
|
||||
print(f" ⚠ Erro ao remover {arquivo}: {e}")
|
||||
|
||||
# Remove o diretório se estiver vazio
|
||||
try:
|
||||
os.rmdir(DIRETORIO_TEMP)
|
||||
print(f" ✓ Diretório temporário removido")
|
||||
except:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f" ⚠ Erro ao limpar arquivos temporários: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Função principal que executa todo o processo."""
|
||||
print("\n" + "="*60)
|
||||
print("ESTOQUE MAR - PROCESSO UNIFICADO")
|
||||
print("="*60)
|
||||
print(f"Início: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("="*60)
|
||||
|
||||
# Criar diretório temporário
|
||||
criar_diretorio_temp()
|
||||
|
||||
# Lista para armazenar os arquivos baixados
|
||||
arquivos_baixados = []
|
||||
|
||||
# 1. Baixar arquivo do Grupo 1 (Lojas)
|
||||
arquivo_loja = processar_download_grupo(
|
||||
LOJAS_GRUPO_1,
|
||||
"GRUPO 1 - LOJAS",
|
||||
"Estoque_mar_loja.xlsx",
|
||||
2 # status_id
|
||||
)
|
||||
if arquivo_loja:
|
||||
arquivos_baixados.append(arquivo_loja)
|
||||
|
||||
# 2. Baixar arquivo do Grupo 2 (VD)
|
||||
arquivo_vd = processar_download_grupo(
|
||||
LOJAS_GRUPO_2,
|
||||
"GRUPO 2 - VD",
|
||||
"Estoque_mar_VD.xlsx",
|
||||
5 # status_id
|
||||
)
|
||||
if arquivo_vd:
|
||||
arquivos_baixados.append(arquivo_vd)
|
||||
|
||||
# 3. Upload para o banco de dados
|
||||
if arquivos_baixados:
|
||||
sucesso_upload = processar_upload_banco(arquivos_baixados)
|
||||
else:
|
||||
print("\n✗ Nenhum arquivo foi baixado. Abortando upload.")
|
||||
sucesso_upload = False
|
||||
|
||||
# 4. Limpar arquivos temporários
|
||||
print(f"\n{'='*60}")
|
||||
print("LIMPANDO ARQUIVOS TEMPORÁRIOS")
|
||||
print(f"{'='*60}")
|
||||
limpar_arquivos_temporarios()
|
||||
|
||||
# Resumo final
|
||||
print("\n" + "="*60)
|
||||
print("RESUMO FINAL")
|
||||
print("="*60)
|
||||
print(f"Arquivos baixados: {len(arquivos_baixados)}/2")
|
||||
print(f"Upload para banco: {'✓ SUCESSO' if sucesso_upload else '✗ FALHA'}")
|
||||
print(f"Fim: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print("="*60 + "\n")
|
||||
|
||||
return sucesso_upload
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user