From e8176e97ce18afb4ce9ab33d5b95e5da963c162c Mon Sep 17 00:00:00 2001 From: "daniel.rodrigues" Date: Fri, 31 Oct 2025 10:21:38 -0300 Subject: [PATCH] att --- extranet_notas_debito.py | 178 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 extranet_notas_debito.py diff --git a/extranet_notas_debito.py b/extranet_notas_debito.py new file mode 100644 index 0000000..2d7d6a9 --- /dev/null +++ b/extranet_notas_debito.py @@ -0,0 +1,178 @@ +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()