import os import requests import pyodbc from datetime import datetime, timedelta OUTPUT_DIR_BASE = r"\\10.77.77.11\Contabilidade\AUTOMAÇÃO\NotadeDebito" DB_CONN = ( "Driver={ODBC Driver 17 for SQL Server};" "Server=10.77.77.10;" "Database=GINSENG;" "UID=andrey;" "PWD=88253332Wa@;" ) # 1️⃣ Token def get_token(): print("🔐 Obtendo token...") r = requests.get("https://api.grupoginseng.com.br/api/tokens") r.raise_for_status() token = r.json()["data"][0]["token"] print("✅ Token obtido com sucesso.") return token # 2️⃣ Última data sincronizada def get_last_invoice_date(cursor): cursor.execute("SELECT MAX(invoiceDate) FROM dbo.DebitNotes WHERE invoiceDate IS NOT NULL") result = cursor.fetchone()[0] if result: print(f"🕓 Última data sincronizada: {result}") return result else: default = datetime.now() - timedelta(days=30) print(f"⚙️ Nenhuma data encontrada, buscando últimos 30 dias ({default.date()})") return default # 3️⃣ Busca com paginação def get_all_documents(token): print("📡 Consultando notas fiscais (paginado)...") url_base = "https://sf-fiscal-api.grupoboticario.digital/v1/debit-notes/documents-list" headers = { "accept": "application/json, text/plain, */*", "authorization": token, "content-type": "application/json", } payload = { "franchiseId": [ "4494", "12522", "12817", "12818", "12820", "12823", "12824", "12826", "12828", "12829", "12830", "12838", "13427", "14617", "14668", "19103", "20005", "20006", "20009", "20056", "20057", "20441", "20683", "20712", "20858", "20968", "20969", "20970", "20979", "20986", "20988", "20989", "20991", "20992", "20993", "20994", "20995", "20996", "20997", "20998", "20999", "21000", "21001", "21007", "21068", "21277", "21278", "21296", "21375", "21381", "21383", "21495", "21624", "21647", "21737", "21738", "21739", "21740", "22448", "22475", "22501", "22526", "22532", "22533", "22541", "22593", "22632", "23156", "23475", "23665", "23701", "23702", "23703", "23704", "23705", "23706", "23707", "23708", "23709", "23711", "23712", "23713", "3546", "4560", "5699", "910173", "910291", "911486", "911487", "911488", "911489", "911490", "911491", "911492", "911509", "911510", "911511", "911512", "911513", "911514", "911515", "911516", "911517", "911518", "911519", "911762", "911766", "911924", "911940", "912242", "912273", "912856", "912857", "912858", "912859" ] } skip, take = 0, 2000 all_docs = [] while True: url = f"{url_base}?cpId=10269&skip={skip}&take={take}" print(f"➡️ Página {skip // take + 1} — buscando registros {skip}–{skip + take}...") r = requests.post(url, headers=headers, json=payload) if r.status_code != 200: print(f"❌ Erro {r.status_code}: {r.text}") break docs = r.json().get("documentsList", []) if not docs: print("✅ Nenhum novo documento encontrado.") break all_docs.extend(docs) print(f"📦 Recebidos {len(docs)} registros (total: {len(all_docs)})") if len(docs) < take: break skip += take return all_docs # 4️⃣ Filtro local por data def filter_documents_by_date(documents, start_date, end_date): filtrados = [] for doc in documents: try: inv_date = datetime.strptime(doc.get("invoiceDate", ""), "%Y-%m-%d") if start_date.date() <= inv_date.date() <= end_date.date(): filtrados.append(doc) except Exception: continue print(f"📅 {len(filtrados)} documentos dentro do intervalo {start_date}–{end_date}") return filtrados # 5️⃣ Inserção e download def record_exists(cursor, doc_id): cursor.execute("SELECT 1 FROM dbo.DebitNotes WHERE id = ?", doc_id) return cursor.fetchone() is not None def insert_record(cursor, doc): cursor.execute(""" INSERT INTO dbo.DebitNotes ( id, debitNoteOrigin, cnpj, cpId, franchiseId, debitNoteNumber, invoiceNumber, invoiceItem, invoiceDate, invoiceDueDate, value, serviceDescription, imageId, notificationRead, notificationReadDate, acknowledged, acknowledgedDate, UUID, imageName, uploadedFile ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( doc.get("id"), doc.get("debitNoteOrigin") or "N/D", doc.get("cnpj") or "", doc.get("cpId"), doc.get("franchiseId"), doc.get("debitNoteNumber") or "", doc.get("invoiceNumber") or "", doc.get("invoiceItem") or "", doc.get("invoiceDate"), doc.get("invoiceDueDate"), doc.get("value") or 0, doc.get("serviceDescription") or "", doc.get("imageId"), 1 if doc.get("notificationRead") else 0, doc.get("notificationReadDate"), 1 if doc.get("acknowledged") else 0, doc.get("acknowledgedDate"), doc.get("UUID"), doc.get("imageName"), 1 if doc.get("uploadedFile") else 0 )) def download_pdf(token, franchise_id, doc_id, image_name, invoice_date): try: url = f"https://sf-fiscal-api.grupoboticario.digital/v1/handle-images/NDEB/{franchise_id}/{doc_id}/{image_name}/download" r = requests.get(url, headers={"authorization": token}) r.raise_for_status() s3_url = r.text.strip() pasta = os.path.join(OUTPUT_DIR_BASE, str(invoice_date)) os.makedirs(pasta, exist_ok=True) file_path = os.path.join(pasta, image_name) pdf = requests.get(s3_url, stream=True) if pdf.status_code == 200: with open(file_path, "wb") as f: for chunk in pdf.iter_content(8192): f.write(chunk) print(f"📥 PDF salvo: {file_path}") except Exception as e: print(f"❌ Erro ao baixar {image_name}: {e}") # 🚀 Main def main(): token = get_token() conn = pyodbc.connect(DB_CONN) cursor = conn.cursor() ultima_data = get_last_invoice_date(cursor) hoje = datetime.now() todos = get_all_documents(token) documentos = filter_documents_by_date(todos, ultima_data, hoje) novos, ignorados = 0, 0 for doc in documentos: if record_exists(cursor, doc["id"]): ignorados += 1 continue insert_record(cursor, doc) novos += 1 download_pdf(token, doc["franchiseId"], doc["id"], doc["imageName"], doc["invoiceDate"]) conn.commit() conn.close() print(f"\n✅ Finalizado. {novos} novos registros, {ignorados} já existiam.") print(f"🕓 Execução concluída em {datetime.now().strftime('%H:%M:%S')}") if __name__ == "__main__": main()