# -*- coding: utf-8 -*- import requests import json import socket import pyodbc import time from requests.exceptions import RequestException from datetime import datetime, timezone, timedelta # URL da API url = "https://mar-orders-bff-api.demanda-abastecimento.grupoboticario.digital/api/orderdraft/order-building-data?draftType=SEM" # Cabeçalhos da requisição headers = { "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": '"Not)A;Brand";v="99", "Google Chrome";v="127", "Chromium";v="127"', "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/127.0.0.0 Safari/537.36" } # Lista de códigos das lojas store_codes = [ "12522", "12817", "12818", "12820", "12823", "12824", "12826", "12828", "12829", "12830", "12838", "13427", "14617", "19103", "20005", "20006", "20009", "20056", "20057", "20441", "20858", "20968", "20969", "20970", "20986", "20988", "20989", "20991", "20992", "20993", "20994", "20995", "20996", "20997", "20998", "20999", "21000", "21001", "21068", "21277", "21278", "21296", "21375", "21381", "21383", "21495", "21624", "21647", "22541", "3546", "4560", "5699", "910173", "910291", "21007", "23665", "23712", "23711", "23702", "23703", "23713", "23708", "23701", "23709","23475","23156","14668", "24253", "24254", "24255", "24258", "24257", "24268", "24269", "24293", "23813", "24449", "24450", "24455", "24458", "24454", "24447", "24448", "24451", "24456", "24457", "24453", "24452" ] # Mapeamento de códigos para nomes de categorias category_map = { "10040": "CUIDADOS COM A PELE", "10090": "HOME CARE", "10060": "DESODORANTES", "10110": "MAQUIAGEM", "10080": "GIFTS", "10120": "OLEOS", "10050": "CUIDADOS FACIAIS", "10170": "UNHAS", "10150": "SOLAR", "10190": "CUIDADOS PETS", "10160": "SUPORTE A VENDA", "10030": "CUIDADOS COM A BARBA", "10130": "PERFUMARIA", "10100": "INFANTIL", "10020": "CABELOS", "10070": "EMBALAGENS", "10140": "SABONETE CORPO", "10010": "ACESSORIOS" } # Mapeamento de códigos para nomes de subcategorias subcategory_map = { "1004020125": "CUIDADOS COM O CORPO", "1006020150": "DESODORANTE FEMININO", "1013020285": "PERFUMARIA FEMININA", "1006020155": "DESODORANTE MASCULINO", "1013020290": "PERFUMARIA MASCULINA", "1001020055": "ORGANIZADOR COSTURAVEL", "1014020315": "MULTIFUNCIONAL", "1019020430": "PETS", "1016020385": "MATERIAL DE APOIO", "1001020030": "ELETRONICOS", "1001020045": "FUNCIONAIS MAQUIAGEM", "1010020225": "PERFUMARIA", "1010020200": "CABES", "1010020205": "CUIDADOS COM O CORPO", "1010020235": "SABONETES", "1016020395": "PRM", "1009020195": "AROMATIZACAO", "1001020025": "CORPO E BANHO", "1015020335": "POS-SOL", "1015020360": "PROTETOR FACIAL", "1015020355": "PROTETOR CORPO", "1014020300": "CORPO", "1005020135": "HIDRATANTES E TRATAMENTOS", "1005020140": "LIMPEZA", "1005020145": "MASCARA FACIAL", "1001020015": "CAPINHA", "1009020140": "LIMPEZA", "1004020120": "CUIDADOS COM AS MAOS", "1001020060": "ORGANIZADOR NAO COSTURAVEL", "1002020085": "CONDICIONADOR", "1004020130": "CUIDADOS COM OS PES", "1002020090": "FINALIZADOR", "1006020160": "DESODORANTE UNISSEX", "1002020105": "TRATAMENTO CABELOS", "1012020275": "CUIDADOS COM O CORPO", "1014020305": "CUIDADOS INTIMOS", "1002020095": "SHAMPOO/PRE-SHAMPOO", "1003020110": "POS-BARBEAR", "1003020115": "PRE-BARBEAR", "1001020005": "BRINQUEDO", "1008020190": "ESTOJO REGULAR", "1011020255": "MAQUIAGEM MULTIFUNCIONAL", "1011020260": "MAQUIAGEM OLHOS", "1011020245": "MAQUIAGEM BOCA", "1001020070": "PINCEIS", "1007020170": "EMBALAGENS VENDAVEIS", "1001020035": "EMBALAGEM PRESENTEAVEL", "1011020265": "MAQUIAGEM ROSTO", "1001020040": "EMBALAGEM PRODUTO", "1011020270": "MAQUIAGEM SOBRANCELHAS", "1013020295": "PERFUMARIA UNISSEX", "1014020310": "MAOS", "1002020100": "STYLING", "1001020010": "CABES", "1002020075": "2 EM 1", "1015020365": "PROTETOR FACIAL COM COR", "1012020280": "MULTIFUNCIONAL", "1010020220": "MAQUIAGEM", "1010020210": "DESODORANTE" } # Configurações de conexão com o banco de dados conn = pyodbc.connect( 'DRIVER={ODBC Driver 18 for SQL Server};' 'SERVER=10.77.77.10;' 'DATABASE=GINSENG;' 'UID=supginseng;' 'PWD=Ginseng@;' 'PORT=1433;' 'TrustServerCertificate=yes' ) def check_internet_connection(): """Verifica se há conexão com a internet""" try: socket.gethostbyname("google.com") return True except socket.error: return False def create_draft_temp_table(cursor): """Cria a tabela draft_temp se ela não existir""" try: # Verifica se a tabela já existe cursor.execute(""" IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'draft_temp' AND schema_id = SCHEMA_ID('dbo')) BEGIN CREATE TABLE dbo.draft_temp ( id INT IDENTITY(1,1) PRIMARY KEY, date DATE DEFAULT CAST(GETDATE() AS DATE), loja_id VARCHAR(50), code VARCHAR(50), description VARCHAR(255), launch VARCHAR(50), deactivation VARCHAR(50), thirdToLastCycleSales INT, secondToLastCycleSales INT, lastCycleSales INT, currentCycleSales INT, nextCycleProjection INT, secondToNextCycleProjection INT, stock_actual INT, stock_inTransit INT, purchaseSuggestion INT, smartPurchase_purchaseSuggestionCycle INT, smartPurchase_nextCyclePurchaseSuggestion INT, pendingOrder INT, salesCurve VARCHAR(50), promotions_description NVARCHAR(MAX), promotions_discountPercent NVARCHAR(MAX), priceSellin DECIMAL(18, 2), businessUnit VARCHAR(50), codCategory VARCHAR(255), criticalItem_dtProvidedRegularization VARCHAR(50), criticalItem_blockedWallet NVARCHAR(MAX), criticalItem_isCritical NVARCHAR(MAX), codSubCategory VARCHAR(255), isProductDeactivated NVARCHAR(MAX), brandGroupCode VARCHAR(50), daysWithoutSales INT, coverageDays INT, hasCoverage VARCHAR(50), thirdToLastCycle VARCHAR(5), secondToLastCycle VARCHAR(5), lastCycle VARCHAR(5), currentCycle VARCHAR(5), nextCycle VARCHAR(5), secondToNextCycle VARCHAR(5), secondToNextCycleEud VARCHAR(5), nextCycleEud VARCHAR(5), thirdToLastCycleEud VARCHAR(5), secondToLastCycleEud VARCHAR(5), lastCycleEud VARCHAR(5), currentCycleEud VARCHAR(5) ) END """) conn.commit() print("Tabela draft_temp verificada/criada com sucesso.") except Exception as e: print(f"Erro ao criar tabela draft_temp: {e}") conn.rollback() raise def create_promo_temp_table(cursor): """Cria a tabela promo_temp se ela não existir""" try: # Verifica se a tabela já existe e exclui para recriar cursor.execute(""" IF EXISTS (SELECT * FROM sys.tables WHERE name = 'promo_temp' AND schema_id = SCHEMA_ID('dbo')) BEGIN DROP TABLE dbo.promo_temp END """) conn.commit() # Cria a tabela promo_temp cursor.execute(""" CREATE TABLE dbo.promo_temp ( id INT IDENTITY(1,1) PRIMARY KEY, loja_id NVARCHAR(MAX) NULL, code NVARCHAR(MAX) NULL, type NVARCHAR(MAX) NULL, target NVARCHAR(MAX) NULL, thirdToLastCycle_discountPercent NVARCHAR(MAX) NULL, thirdToLastCycle_description NVARCHAR(MAX) NULL, secondToLastCycle_discountPercent NVARCHAR(MAX) NULL, secondToLastCycle_description NVARCHAR(MAX) NULL, lastCycle_discountPercent NVARCHAR(MAX) NULL, lastCycle_description NVARCHAR(MAX) NULL, currentCycle_discountPercent NVARCHAR(MAX) NULL, currentCycle_description NVARCHAR(MAX) NULL, nextCycle_discountPercent NVARCHAR(MAX) NULL, nextCycle_description NVARCHAR(MAX) NULL, secondToNextCycle_discountPercent NVARCHAR(MAX) NULL, secondToNextCycle_description NVARCHAR(MAX) NULL, thirdToLastCycleEud_discountPercent NVARCHAR(MAX) NULL, thirdToLastCycleEud_description NVARCHAR(MAX) NULL, secondToLastCycleEud_discountPercent NVARCHAR(MAX) NULL, secondToLastCycleEud_description NVARCHAR(MAX) NULL, lastCycleEud_discountPercent NVARCHAR(MAX) NULL, lastCycleEud_description NVARCHAR(MAX) NULL, currentCycleEud_discountPercent NVARCHAR(MAX) NULL, currentCycleEud_description NVARCHAR(MAX) NULL, nextCycleEud_discountPercent NVARCHAR(MAX) NULL, nextCycleEud_description NVARCHAR(MAX) NULL, secondToNextCycleEud_discountPercent NVARCHAR(MAX) NULL, secondToNextCycleEud_description NVARCHAR(MAX) NULL, dt_atualizacao DATETIME DEFAULT GETDATE() ) """) conn.commit() print("Tabela promo_temp verificada/criada com sucesso.") except Exception as e: print(f"Erro ao criar tabela promo_temp: {e}") conn.rollback() raise def process_and_insert_promo_data(store_code, response_data, cursor): """Processa os dados da API e insere na tabela promo_temp""" try: base = response_data.get('data', {}) # Definir os ciclos normais e EUD com seus valores do JSON cycle_values = { 'thirdToLastCycle': base.get('thirdToLastCycle', ''), 'secondToLastCycle': base.get('secondToLastCycle', ''), 'lastCycle': base.get('lastCycle', ''), 'currentCycle': base.get('currentCycle', ''), 'nextCycle': base.get('nextCycle', ''), 'secondToNextCycle': base.get('secondToNextCycle', ''), 'secondToNextCycleEud': base.get('secondToNextCycleEud', ''), 'nextCycleEud': base.get('nextCycleEud', ''), 'thirdToLastCycleEud': base.get('thirdToLastCycleEud', ''), 'secondToLastCycleEud': base.get('secondToLastCycleEud', ''), 'lastCycleEud': base.get('lastCycleEud', ''), 'currentCycleEud': base.get('currentCycleEud', ''), } products = base.get('products', []) if not products: return 0 promo_count = 0 for product in products: code = product.get('code') if not code: continue promotions = product.get('promotions', []) if not promotions: continue # Agrupar todas as promoções do produto em um único registro promo_data = { 'loja_id': store_code, 'code': code, 'type': '', 'target': '', } # Dicionários temporários para acumular valores por ciclo cycle_discounts = {} cycle_descriptions = {} types_list = [] targets_list = [] for promotion in promotions: promo_type = promotion.get('type', '') promo_target = promotion.get('target', '') if promo_type and promo_type not in types_list: types_list.append(promo_type) if promo_target and promo_target not in targets_list: targets_list.append(promo_target) cycle = promotion.get('cycle') if not cycle: continue # Identificar qual ciclo corresponde a esta promoção for cycle_key, cycle_value in cycle_values.items(): if cycle == cycle_value and cycle_value: discount = str(promotion.get('discountPercent', '')) description = promotion.get('description', '') # Acumular valores com separador " | " if cycle_key not in cycle_discounts: cycle_discounts[cycle_key] = [] cycle_descriptions[cycle_key] = [] if discount: cycle_discounts[cycle_key].append(discount) if description: cycle_descriptions[cycle_key].append(description) break # Montar o registro final com valores concatenados promo_data['type'] = ' | '.join(types_list) if types_list else '' promo_data['target'] = ' | '.join(targets_list) if targets_list else '' for cycle_key in cycle_values.keys(): if cycle_key in cycle_discounts: promo_data[f'{cycle_key}_discountPercent'] = ' | '.join(cycle_discounts[cycle_key]) if cycle_key in cycle_descriptions: promo_data[f'{cycle_key}_description'] = ' | '.join(cycle_descriptions[cycle_key]) # Inserir o registro de promoção na tabela promo_temp columns = ['loja_id', 'code', 'type', 'target', 'thirdToLastCycle_discountPercent', 'thirdToLastCycle_description', 'secondToLastCycle_discountPercent', 'secondToLastCycle_description', 'lastCycle_discountPercent', 'lastCycle_description', 'currentCycle_discountPercent', 'currentCycle_description', 'nextCycle_discountPercent', 'nextCycle_description', 'secondToNextCycle_discountPercent', 'secondToNextCycle_description', 'thirdToLastCycleEud_discountPercent', 'thirdToLastCycleEud_description', 'secondToLastCycleEud_discountPercent', 'secondToLastCycleEud_description', 'lastCycleEud_discountPercent', 'lastCycleEud_description', 'currentCycleEud_discountPercent', 'currentCycleEud_description', 'nextCycleEud_discountPercent', 'nextCycleEud_description', 'secondToNextCycleEud_discountPercent', 'secondToNextCycleEud_description'] values = [promo_data.get(col, None) for col in columns] placeholders = ', '.join(['?' for _ in columns]) columns_str = ', '.join(columns) query = f""" INSERT INTO [GINSENG].[dbo].[promo_temp] ({columns_str}) VALUES ({placeholders}) """ cursor.execute(query, values) promo_count += 1 conn.commit() return promo_count except Exception as e: print(f"Erro ao processar dados de promoção da loja {store_code}: {e}") conn.rollback() return 0 def process_and_insert_data(store_code, response_data, cursor): """Processa os dados da API e insere na tabela draft_temp""" try: # Limpar dados da loja no banco antes de inserir novos dados delete_sql = "DELETE FROM draft_temp WHERE loja_id = ?" cursor.execute(delete_sql, (store_code,)) base = response_data.get('data', {}) products = base.get('products', []) current_cycle = base.get('currentCycle', '') # Extrair valores de ciclo do JSON cycle_data = { 'thirdToLastCycle': base.get('thirdToLastCycle', ''), 'secondToLastCycle': base.get('secondToLastCycle', ''), 'lastCycle': base.get('lastCycle', ''), 'currentCycle': base.get('currentCycle', ''), 'nextCycle': base.get('nextCycle', ''), 'secondToNextCycle': base.get('secondToNextCycle', ''), 'secondToNextCycleEud': base.get('secondToNextCycleEud', ''), 'nextCycleEud': base.get('nextCycleEud', ''), 'thirdToLastCycleEud': base.get('thirdToLastCycleEud', ''), 'secondToLastCycleEud': base.get('secondToLastCycleEud', ''), 'lastCycleEud': base.get('lastCycleEud', ''), 'currentCycleEud': base.get('currentCycleEud', ''), } registros = [] for product in products: promotions = product.get('promotions', []) filtered_promotions = [promo for promo in promotions if promo.get('cycle') == current_cycle] if filtered_promotions: promotion_description = " | ".join(promo.get('description', '') for promo in filtered_promotions) promotion_discount = " | ".join(str(promo.get('discountPercent', '')) for promo in filtered_promotions) else: promotion_description = '' promotion_discount = '' # Busca o nome da categoria no dicionário cod_category = product.get('codCategory', '') category_name = category_map.get(str(cod_category), '') # Busca o nome da subcategoria no dicionário cod_subcategory = product.get('codSubCategory', '') subcategory_name = subcategory_map.get(str(cod_subcategory), '') # Corrigir o campo criticalItem_dtProvidedRegularization dt_provided_regularization = product.get('criticalItem', {}).get('dtProvidedRegularization', '') if isinstance(dt_provided_regularization, list): if not dt_provided_regularization or dt_provided_regularization[0] is None: dt_provided_regularization = '' elif dt_provided_regularization is None: dt_provided_regularization = '' # Corrigindo o campo daysWithoutSales e coverageDays days_without_sales = product.get('daysWithoutSales', 0) coverage_days = product.get('coverageDays', 0) if days_without_sales is None: days_without_sales = 0 if coverage_days is None: coverage_days = 0 registro = ( store_code, product.get('code'), product.get('description'), product.get('launch'), product.get('deactivation'), product.get('sales', {}).get('thirdToLastCycleSales', 0), product.get('sales', {}).get('secondToLastCycleSales', 0), product.get('sales', {}).get('lastCycleSales', 0), product.get('sales', {}).get('currentCycleSales', 0), product.get('sales', {}).get('nextCycleProjection', 0), product.get('sales', {}).get('secondToNextCycleProjection', 0), product.get('stock', {}).get('actual', 0), product.get('stock', {}).get('inTransit', 0), product.get('purchaseSuggestion', 0), product.get('smartPurchase', {}).get('purchaseSuggestionCycle', 0), product.get('smartPurchase', {}).get('nextCyclePurchaseSuggestion', 0), product.get('pendingOrder', 0), product.get('salesCurve', ''), promotion_description, promotion_discount, product.get('priceSellin', 0.0), product.get('businessUnit', ''), category_name, dt_provided_regularization, product.get('criticalItem', {}).get('blockedWallet', False), product.get('criticalItem', {}).get('isCritical', False), subcategory_name, product.get('isProductDeactivated', False), product.get('brandGroupCode', ''), days_without_sales, coverage_days, product.get('hasCoverage', False), cycle_data['thirdToLastCycle'], cycle_data['secondToLastCycle'], cycle_data['lastCycle'], cycle_data['currentCycle'], cycle_data['nextCycle'], cycle_data['secondToNextCycle'], cycle_data['secondToNextCycleEud'], cycle_data['nextCycleEud'], cycle_data['thirdToLastCycleEud'], cycle_data['secondToLastCycleEud'], cycle_data['lastCycleEud'], cycle_data['currentCycleEud'] ) registros.append(registro) if registros: sql = """ INSERT INTO draft_temp ( loja_id, code, description, launch, deactivation, thirdToLastCycleSales, secondToLastCycleSales, lastCycleSales, currentCycleSales, nextCycleProjection, secondToNextCycleProjection, stock_actual, stock_inTransit, purchaseSuggestion, smartPurchase_purchaseSuggestionCycle, smartPurchase_nextCyclePurchaseSuggestion, pendingOrder, salesCurve, promotions_description, promotions_discountPercent, priceSellin, businessUnit, codCategory, criticalItem_dtProvidedRegularization, criticalItem_blockedWallet, criticalItem_isCritical, codSubCategory, isProductDeactivated, brandGroupCode, daysWithoutSales, coverageDays, hasCoverage, thirdToLastCycle, secondToLastCycle, lastCycle, currentCycle, nextCycle, secondToNextCycle, secondToNextCycleEud, nextCycleEud, thirdToLastCycleEud, secondToLastCycleEud, lastCycleEud, currentCycleEud ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """ cursor.executemany(sql, registros) conn.commit() return len(registros) return 0 except Exception as e: print(f"Erro ao processar dados da loja {store_code}: {e}") conn.rollback() raise def fetch_and_insert_data(store_code, index, total, cursor, retry_count=1): """Baixa os dados da API e insere diretamente no banco""" attempt = 0 while attempt < retry_count: try: # Definindo storeType com base no código da loja if store_code == "21007": store_type = "BOT" elif store_code in ["910173", "910291"]: store_type = "QDB" else: store_type = "BOT" # Dados da requisição com o código da loja data = { "storeCode": store_code, "useId": 163165, "storeType": store_type, "generateNew": False } # Fazendo a requisição POST response = requests.post(url, headers=headers, json=data) response.raise_for_status() # Requisição bem-sucedida response_data = response.json() # Processa e insere os dados na tabela draft_temp num_products = process_and_insert_data(store_code, response_data, cursor) # Processa e insere os dados na tabela promo num_promos = process_and_insert_promo_data(store_code, response_data, cursor) print(f"{index}/{total}: Loja {store_code} processada com sucesso ({num_products} produtos inseridos, {num_promos} promoções inseridas).") return True except RequestException as e: print(f"{index}/{total}: Erro na requisição para a loja {store_code}: {e}") except Exception as e: print(f"{index}/{total}: Erro inesperado para a loja {store_code}: {e}") attempt += 1 print(f"{index}/{total}: Tentativa {attempt} de {retry_count} para a loja {store_code}.") time.sleep(5) print(f"{index}/{total}: Falha ao processar a loja {store_code} após {retry_count} tentativas.") return False def finalize_tables(cursor): """ Finaliza o processo: 1. Atualiza dbo.draft_historico com os dados da dbo.draft_temp 2. Exclui a tabela dbo.draft_temp 3. Atualiza dbo.promo com os dados da dbo.promo_temp 4. Exclui a tabela dbo.promo_temp """ try: print("\n=== Iniciando finalização das tabelas ===") # Passo 1: Atualizar draft_historico print("Passo 1: Atualizando dbo.draft_historico...") # Obter a data de hoje today = datetime.now().strftime("%Y-%m-%d") print(f"Data de hoje: {today}") # Verificar se já existem dados para hoje cursor.execute("SELECT COUNT(*) FROM dbo.draft_historico WHERE CAST(data AS DATE) = ?", (today,)) count = cursor.fetchone()[0] if count > 0: print(f"Encontrados {count} registros para a data {today}. Excluindo...") cursor.execute("DELETE FROM dbo.draft_historico WHERE CAST(data AS DATE) = ?", (today,)) conn.commit() print(f"Registros da data {today} excluídos com sucesso.") else: print(f"Nenhum registro encontrado para a data {today}.") # Inserir dados da tabela draft_temp na draft_historico print("Inserindo dados da dbo.draft_temp na dbo.draft_historico...") cursor.execute(""" INSERT INTO dbo.draft_historico ( loja_id, code, description, launch, deactivation, thirdtolastcyclesales, secondtolastcyclesales, lastcyclesales, currentcyclesales, nextcycleprojection, secondtonextcycleprojection, stock_actual, stock_intransit, purchasesuggestion, smartpurchase_purchasesuggestioncycle, smartpurchase_nextcyclepurchasesuggestion, pendingorder, salescurve, promotions_description, promotions_discountpercent, pricesellin, businessunit, codcategory, criticalitem_dtprovidedregularization, criticalitem_blockedwallet, criticalitem_iscritical, codsubcategory, isproductdeactivated, brandgroupcode, dayswithoutsales, coveragedays, hascoverage, data, thirdToLastCycle, secondToLastCycle, lastCycle, currentCycle, nextCycle, secondToNextCycle, secondToNextCycleEud, nextCycleEud, thirdToLastCycleEud, secondToLastCycleEud, lastCycleEud, currentCycleEud ) SELECT loja_id, code, description, launch, deactivation, thirdToLastCycleSales, secondToLastCycleSales, lastCycleSales, currentCycleSales, nextCycleProjection, secondToNextCycleProjection, stock_actual, stock_inTransit, purchaseSuggestion, smartPurchase_purchaseSuggestionCycle, smartPurchase_nextCyclePurchaseSuggestion, pendingOrder, salesCurve, promotions_description, promotions_discountPercent, priceSellin, businessUnit, codCategory, criticalItem_dtProvidedRegularization, criticalItem_blockedWallet, criticalItem_isCritical, codSubCategory, isProductDeactivated, brandGroupCode, daysWithoutSales, coverageDays, hasCoverage, date, thirdToLastCycle, secondToLastCycle, lastCycle, currentCycle, nextCycle, secondToNextCycle, secondToNextCycleEud, nextCycleEud, thirdToLastCycleEud, secondToLastCycleEud, lastCycleEud, currentCycleEud FROM dbo.draft_temp """) conn.commit() # Verificar quantos registros foram inseridos cursor.execute("SELECT @@ROWCOUNT") inserted_count = cursor.fetchone()[0] print(f"{inserted_count} registros inseridos na dbo.draft_historico com sucesso.") # Passo 2: Excluir a tabela draft_temp print("Passo 2: Excluindo tabela dbo.draft_temp...") cursor.execute(""" IF EXISTS (SELECT * FROM sys.tables WHERE name = 'draft_temp' AND schema_id = SCHEMA_ID('dbo')) BEGIN DROP TABLE dbo.draft_temp END """) conn.commit() print("Tabela dbo.draft_temp excluída com sucesso.") # Passo 3: Atualizar tabela promo print("Passo 3: Atualizando dbo.promo...") # Limpar a tabela promo e resetar o identity cursor.execute(""" TRUNCATE TABLE [GINSENG].[dbo].[promo] """) conn.commit() print("Tabela dbo.promo limpa com sucesso (TRUNCATE reseta o identity).") # Inserir dados da tabela promo_temp na promo print("Inserindo dados da dbo.promo_temp na dbo.promo...") cursor.execute(""" INSERT INTO dbo.promo ( loja_id, code, type, target, thirdToLastCycle_discountPercent, thirdToLastCycle_description, secondToLastCycle_discountPercent, secondToLastCycle_description, lastCycle_discountPercent, lastCycle_description, currentCycle_discountPercent, currentCycle_description, nextCycle_discountPercent, nextCycle_description, secondToNextCycle_discountPercent, secondToNextCycle_description, thirdToLastCycleEud_discountPercent, thirdToLastCycleEud_description, secondToLastCycleEud_discountPercent, secondToLastCycleEud_description, lastCycleEud_discountPercent, lastCycleEud_description, currentCycleEud_discountPercent, currentCycleEud_description, nextCycleEud_discountPercent, nextCycleEud_description, secondToNextCycleEud_discountPercent, secondToNextCycleEud_description, dt_atualizacao ) SELECT loja_id, code, type, target, thirdToLastCycle_discountPercent, thirdToLastCycle_description, secondToLastCycle_discountPercent, secondToLastCycle_description, lastCycle_discountPercent, lastCycle_description, currentCycle_discountPercent, currentCycle_description, nextCycle_discountPercent, nextCycle_description, secondToNextCycle_discountPercent, secondToNextCycle_description, thirdToLastCycleEud_discountPercent, thirdToLastCycleEud_description, secondToLastCycleEud_discountPercent, secondToLastCycleEud_description, lastCycleEud_discountPercent, lastCycleEud_description, currentCycleEud_discountPercent, currentCycleEud_description, nextCycleEud_discountPercent, nextCycleEud_description, secondToNextCycleEud_discountPercent, secondToNextCycleEud_description, dt_atualizacao FROM dbo.promo_temp """) conn.commit() # Verificar quantos registros foram inseridos cursor.execute("SELECT @@ROWCOUNT") promo_inserted_count = cursor.fetchone()[0] print(f"{promo_inserted_count} registros inseridos na dbo.promo com sucesso.") # Passo 4: Excluir a tabela promo_temp print("Passo 4: Excluindo tabela dbo.promo_temp...") cursor.execute(""" IF EXISTS (SELECT * FROM sys.tables WHERE name = 'promo_temp' AND schema_id = SCHEMA_ID('dbo')) BEGIN DROP TABLE dbo.promo_temp END """) conn.commit() print("Tabela dbo.promo_temp excluída com sucesso.") print("=== Finalização das tabelas concluída com sucesso ===\n") return True except Exception as e: print(f"Erro ao finalizar tabelas: {e}") conn.rollback() return False def update_api_status(status): """Atualiza o status da API""" try: url_status = "https://api.grupoginseng.com.br/api/status/1" # Definir fuso horário de São Paulo (UTC-3) sao_paulo_offset = timedelta(hours=-3) # Gerar data/hora atual no formato YYYY-MM-DD HH:MM:SS com UTC-3 current_datetime = datetime.now(timezone(sao_paulo_offset)).strftime("%Y-%m-%d %H:%M:%S") # Montar o payload payload = { "STATUS": status, "DATA": current_datetime } # Cabeçalhos headers_status = { "Content-Type": "application/json" } # Enviar PUT request response = requests.put(url_status, json=payload, headers=headers_status) print("Hora enviada:", current_datetime) print("Status Code:", response.status_code) print("Response Body:", response.text) except Exception as e: print(f"Erro ao atualizar status da API: {e}") def main(): """Função principal""" if not check_internet_connection(): print("Sem conexão com a internet. Verifique sua conexão e tente novamente.") update_api_status("FAIL") return cursor = conn.cursor() try: # Criar a tabela draft_temp se não existir create_draft_temp_table(cursor) # Criar a tabela promo_temp create_promo_temp_table(cursor) failed_stores = [] total = len(store_codes) # Processa todas as lojas for index, store_code in enumerate(store_codes, start=1): success = fetch_and_insert_data(store_code, index, total, cursor) if not success: failed_stores.append(store_code) # Tenta novamente as lojas que falharam if failed_stores: print("\nTentando novamente as lojas que falharam.") retry_count = 1 for attempt in range(1, retry_count + 1): retry_failed_stores = [] for store_code in failed_stores: index = store_codes.index(store_code) + 1 success = fetch_and_insert_data(store_code, index, total, cursor) if not success: retry_failed_stores.append(store_code) failed_stores = retry_failed_stores if not failed_stores: print("\nTodos os arquivos foram processados com sucesso.") break if failed_stores: print(f"Tentativa {attempt} de {retry_count} para as lojas que falharam.") time.sleep(10) # Se ainda houver lojas com falha após todas as tentativas if failed_stores: print(f"\nNão foi possível processar algumas lojas: {failed_stores}") else: print("\nTodos os arquivos foram processados com sucesso.") # Finalizar tabelas SEMPRE, independente de ter lojas com falha ou não if finalize_tables(cursor): # Se a finalização foi bem-sucedida, verifica se houve lojas com falha if failed_stores: update_api_status("FAIL") else: update_api_status("OK") else: # Se a finalização falhou, sempre marca como FAIL update_api_status("FAIL") except Exception as e: print(f"Erro durante a execução: {e}") update_api_status("FAIL") finally: cursor.close() conn.close() print("\nProcesso finalizado.") if __name__ == "__main__": main()