Python ve openpyxl ile Excel Raporlama ve Veri Doğrulama Otomasyonu

Endüstriyel üretim tesislerinde, kalite kontrol laboratuvarlarında ve mühendislik departmanlarında her gün binlerce ölçüm verisi üretilir. CNC tezgahları, spektrometreler, çekme testi cihazları veya kurumsal ERP sistemleri ham verileri genellikle CSV, TXT ya da biçimlendirilmemiş ham tablolar halinde dışa aktarır. Bu verileri her hafta elle kopyalayıp Excel sayfalarına yapıştırmak, başlıkları tek tek boyamak, sınır değerleri kontrol edip renkli uyarılar eklemek ve formül yazmak hem saatler süren bir iş gücü kaybına hem de kritik insan hatalarına davetiye çıkarır.

Daha önce ofis verimliliği alanında paylaştığımız Excel Çevrimdışı Barkod ve QR Kod Oluşturma çözümlerimiz VBA makroları ile pratik sonuçlar üretirken; bağımsız, platformlar arası ve arka planda çalışan uçtan uca bir otomasyon zinciri kurmak için Python en güçlü silahtır. Hazırladığımız bu otomasyon scriptini auto-py-to-exe ile Python Dosyalarını EXE’ye Dönüştürme rehberimizi izleyerek ofisteki herhangi bir bilgisayarda Python kurulu olmasa dahi tek tıkla çalışan bir masaüstü aracına dönüştürebiliriz. Bu rehberde, openpyxl kütüphanesiyle kurumsal şablonlarda Excel raporu üretmeyi, veri doğrulama (Data Validation) kuralları tanımlamayı ve dinamik formüller inşa etmeyi adım adım öğreniyoruz.

Neden pandas Yerine Doğrudan openpyxl?

Veri analizi dünyasında Pandas kütüphanesi devasa veri kümelerini filtrelemek ve işlemek için vazgeçilmezdir. Ancak bir veri çerçevesini doğrudan df.to_excel() ile dışa aktardığınızda karşınıza renksiz, dar sütunlu, biçimlendirilmemiş ve formül içermeyen ham bir tablo çıkar. openpyxl ise Excel’in Office Open XML (XLSX) dosya yapısına doğrudan nüfuz ederek şu imkanları sunar:

  • Kurumsal Tipografi ve Renkler: Yazı tipi (Font), boyut, hücre dolgusu (PatternFill) ve kenarlık (Border) stillerini piksel hassasiyetinde yönetme.
  • Canlı Excel Formülleri: Statik değerler yerine hücrelere doğrudan dinamik formüller (SUM, AVERAGE, COUNTIF vb.) yazarak dosya açıldığında Excel motorunun hesaplama yapmasını sağlama.
  • Veri Doğrulama (Data Validation): Hücrelere açılır liste (dropdown menu) veya belirli sayısal aralık kısıtlamaları koyarak kullanıcıların hatalı veri girişini engelleme.
  • Koşullu Biçimlendirme (Conditional Formatting): Tolerans dışı ölçümleri veya hatalı parçaları otomatik olarak kırmızı/sarı renkle vurgulama.
  • Otomatik Sütun Genişliği: İçeriğe göre sütunları optimize ederek ### taşma hatalarını ortadan kaldırma.

Geliştirme Ortamı ve Gerekli Kütüphanelerin Kurulumu

Projemiz için standart Python ortamına yalnızca openpyxl paketini eklememiz yeterlidir. Komut satırından aşağıdaki komutu çalıştırarak kurulumu tamamlayın:

pip install openpyxl

Sıfırdan Kurumsal Kalite Kontrol Raporu Üretim Scripti

Aşağıdaki script, talaşlı imalat veya döküm parçalarının ölçüm verilerini alarak, kurumsal lacivert başlık temasına sahip, tolerans dışı parçaları renklendiren ve otomatik özet istatistikler hesaplayan eksiksiz bir endüstriyel rapor üretir:

import os
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
from openpyxl.worksheet.datavalidation import DataValidation

def kurumsal_kalite_raporu_olustur(dosya_adi="Endustriyel_Kalite_Raporu.xlsx"):
    # Yeni bir çalisma kitabi baslat
    wb = Workbook()
    ws = wb.active
    ws.title = "Kalite Kontrol Verileri"
    
    # Kılavuz çizgilerini açık tut
    ws.views.sheetView[0].showGridLines = True

    # --- Kurumsal Renk ve Stil Sabitleri ---
    navy_header_fill = PatternFill(start_color="1B365D", end_color="1B365D", fill_type="solid")
    header_font = Font(name="Segoe UI", size=11, bold=True, color="FFFFFF")
    
    title_font = Font(name="Segoe UI", size=16, bold=True, color="1B365D")
    meta_font = Font(name="Segoe UI", size=10, italic=True, color="595959")
    bold_cell_font = Font(name="Segoe UI", size=10, bold=True, color="000000")
    data_font = Font(name="Segoe UI", size=10, color="000000")
    
    # Kenarlık Stilleri
    thin_border = Border(
        left=Side(style="thin", color="D9D9D9"),
        right=Side(style="thin", color="D9D9D9"),
        top=Side(style="thin", color="D9D9D9"),
        bottom=Side(style="thin", color="D9D9D9")
    )
    total_top_border = Side(style="thin", color="000000")
    total_bottom_border = Side(style="double", color="000000")
    summary_border = Border(top=total_top_border, bottom=total_bottom_border)

    # Durum Dolguları (Koşullu Görsel Vurgu)
    pass_fill = PatternFill(start_color="E2EFDA", end_color="E2EFDA", fill_type="solid") # Açık Yeşil
    fail_fill = PatternFill(start_color="FCE4D6", end_color="FCE4D6", fill_type="solid") # Açık Kırmızı
    warn_fill = PatternFill(start_color="FFF2CC", end_color="FFF2CC", fill_type="solid") # Açık Sarı

    # Hizalama Seçenekleri
    center_align = Alignment(horizontal="center", vertical="center")
    left_align = Alignment(horizontal="left", vertical="center")
    right_align = Alignment(horizontal="right", vertical="center")

    # --- 1. Rapor Başlık Bloğu ---
    ws.merge_cells("A1:F1")
    ws["A1"] = "KARDÖKMAK A.Ş. — MEKANİK İMALAT KALİTE DENETİM RAPORU"
    ws["A1"].font = title_font
    ws["A1"].alignment = left_align
    ws.row_dimensions[1].height = 30

    ws["A2"] = "Denetim Tarihi: 2026-09-23 | Vardiya: 1. Vardiya | Rapor Sorumlusu: Kalite Güvence Birimi"
    ws["A2"].font = meta_font
    ws.row_dimensions[2].height = 18

    # --- 2. Tablo Başlıkları ---
    headers = [
        "Parça Kodu", 
        "Nominal Ölçü (mm)", 
        "Tolerans (±mm)", 
        "Ölçülen Değer (mm)", 
        "Sapma (mm)", 
        "Kalite Kararı"
    ]
    
    start_row = 4
    ws.row_dimensions[start_row].height = 25
    for col_idx, header_text in enumerate(headers, start=1):
        cell = ws.cell(row=start_row, column=col_idx, value=header_text)
        cell.fill = navy_header_fill
        cell.font = header_font
        cell.alignment = center_align

    # --- 3. Örnek İmalat Ölçüm Verileri ---
    ham_veriler = [
        ("AKS-4011", 120.00, 0.05, 120.02),
        ("AKS-4012", 120.00, 0.05, 120.04),
        ("AKS-4013", 120.00, 0.05, 120.09), # Tolerans Dışı (Red)
        ("AKS-4014", 120.00, 0.05, 119.98),
        ("AKS-4015", 120.00, 0.05, 120.01),
        ("AKS-4016", 120.00, 0.05, 120.06), # Şartlı Kabul Sınırı
        ("AKS-4017", 120.00, 0.05, 119.95),
        ("AKS-4018", 120.00, 0.05, 120.00),
    ]

    current_row = start_row + 1
    for parca, nominal, tol, olculen in ham_veriler:
        ws.cell(row=current_row, column=1, value=parca).alignment = center_align
        ws.cell(row=current_row, column=2, value=nominal).number_format = "0.00"
        ws.cell(row=current_row, column=3, value=tol).number_format = "0.00"
        ws.cell(row=current_row, column=4, value=olculen).number_format = "0.00"
        
        # Dinamik Excel Sapma Formülü: Ölçülen - Nominal
        sapma_formulu = f"=D{current_row}-B{current_row}"
        ws.cell(row=current_row, column=5, value=sapma_formulu).number_format = "+0.00;-0.00;0.00"
        
        # Dinamik Excel Karar Formülü
        karar_formulu = f'=IF(ABS(E{current_row})<=C{current_row},"UYGUN",IF(ABS(E{current_row})<=(C{current_row}*1.5),"ŞARTLI KABUL","RED"))'
        karar_cell = ws.cell(row=current_row, column=6, value=karar_formulu)
        karar_cell.alignment = center_align

        # Hücreleri Stillendir
        for c in range(1, 7):
            cell = ws.cell(row=current_row, column=c)
            cell.font = data_font
            cell.border = thin_border
            if c in (2, 3, 4, 5):
                cell.alignment = right_align

        # Ön Koşullu Renk Ataması (Hızlı Görsel Analiz)
        sapma_degeri = round(abs(olculen - nominal), 4)
        if sapma_degeri <= tol:
            karar_cell.fill = pass_fill
        elif sapma_degeri <= (tol * 1.5):
            karar_cell.fill = warn_fill
        else:
            karar_cell.fill = fail_fill
            karar_cell.font = Font(name="Segoe UI", size=10, bold=True, color="C00000")

        ws.row_dimensions[current_row].height = 20
        current_row += 1

    # --- 4. İstatistik ve Toplam Formülleri Satırı ---
    end_data_row = current_row - 1
    ws.row_dimensions[current_row].height = 22
    
    ws.cell(row=current_row, column=1, value="ORTALAMA / GENEL TOPLAM").font = bold_cell_font
    ws.cell(row=current_row, column=1).alignment = left_align
    
    # Ortalama Ölçülen Değer Formülü
    avg_cell = ws.cell(row=current_row, column=4, value=f"=AVERAGE(D5:D{end_data_row})")
    avg_cell.font = bold_cell_font
    avg_cell.number_format = "0.000"
    avg_cell.alignment = right_align

    # Ortalama Sapma Formülü
    avg_sapma = ws.cell(row=current_row, column=5, value=f"=AVERAGE(E5:E{end_data_row})")
    avg_sapma.font = bold_cell_font
    avg_sapma.number_format = "+0.000;-0.000;0.000"
    avg_sapma.alignment = right_align

    # Uygunluk Oranı Metni
    uygunluk_cell = ws.cell(row=current_row, column=6, value=f'=COUNTIF(F5:F{end_data_row},"UYGUN")&" / "&COUNTA(F5:F{end_data_row})')
    uygunluk_cell.font = bold_cell_font
    uygunluk_cell.alignment = center_align

    for c in range(1, 7):
        ws.cell(row=current_row, column=c).border = summary_border

    # --- 5. Veri Doğrulama (Açılır Liste Kuralı Tanımlama) ---
    dv = DataValidation(type="list", formula1='"UYGUN,ŞARTLI KABUL,RED"', allow_blank=False)
    dv.error ='Lütfen sadece UYGUN, ŞARTLI KABUL veya RED değerlerinden birini seçin.'
    dv.errorTitle = 'Geçersiz Kalite Kararı'
    dv.prompt = 'Kalite sonucunu listeden seçebilirsiniz.'
    dv.promptTitle = 'Karar Girişi'
    
    ws.add_data_validation(dv)
    dv.add(f"F5:F{end_data_row}")

    # --- 6. Otomatik Sütun Genişliği Hesaplama ---
    for col in ws.columns:
        max_len = 0
        col_letter = get_column_letter(col[0].column)
        for cell in col:
            # Birleştirilmiş başlık hücresini sütun genişliği hesabına katma
            if cell.row == 1 and cell.column != 1:
                continue
            if cell.value:
                # Formül ise tahmini uzunluk ver
                deger_str = str(cell.value)
                if deger_str.startswith("="):
                    deger_str = "12345678"
                max_len = max(max_len, len(deger_str))
        ws.column_dimensions[col_letter].width = max(max_len + 5, 14)

    # Dosyayı Kaydet
    wb.save(dosya_adi)
    print(f"Rapor basariyla olusturuldu: {dosya_adi}")

if __name__ == "__main__":
    kurumsal_kalite_raporu_olustur()

Dinamik Formüller ve Excel Fonksiyonlarının Enjeksiyonu

Yukarıdaki scriptte dikkat edilmesi gereken en mühim teknik detay, sapma ve karar sütunlarına sabit sayısal sonuçlar yerine doğrudan Excel formül dizgelerinin yazılmasıdır. Örneğin:

# Hücreye Excel formülü atama
sapma_formulu = f"=D{current_row}-B{current_row}"
karar_formulu = f'=IF(ABS(E{current_row})<=C{current_row},"UYGUN",IF(ABS(E{current_row})<=(C{current_row}*1.5),"ŞARTLI KABUL","RED"))'

Bu yaklaşım sayesinde kalite mühendisi veya operatör Excel dosyasını açıp ölçülen değerde bir düzeltme yaptığında, sapma ve kalite kararı otomatik olarak yeniden hesaplanır. Rapor statik bir çıktı olmaktan çıkıp etkileşimli bir mühendislik aracına dönüşür.

Veri Doğrulama (Data Validation) ile Kullanıcı Hatalarını Engelleme

Raporu dolduracak saha çalışanlarının tabloya "KABUL", "OK", "UYGUNDUR", "HAYIR" gibi standart dışı metinler yazmasını önlemek için DataValidation sınıfı kullanılır. Scriptimizde tanımladığımız açılır menü kuralı, Excel'in veri doğrulama motorunu tetikleyerek hücre tıklandığında yalnızca belirlenen seçenekleri sunar ve farklı bir giriş yapıldığında uyarı penceresi fırlatır.

Sütun Genişliği Optimizasyonu ve `###` Hatasının Önlenmesi

Excel kullanıcılarının en çok canını sıkan durumlardan biri, sayısal bir değerin sütun genişliğini aşması durumunda hücrede beliren ### gösterimidir. Scriptin sonunda yer alan döngü, her sütundaki en uzun metni (veya formül karakterini) tarar ve sütun genişliğini otomatik olarak dinamik biçimde boyutlandırır.

Scripti Tek Tıkla Çalışan Masaüstü EXE Aracına Dönüştürme

Hazırladığınız bu Python scriptini üretim sahasındaki veya idari birimlerdeki çalışma arkadaşlarınıza dağıtırken onların bilgisayarına Python veya kütüphane kurmak zorunda değilsiniz. Daha önce detaylandırdığımız auto-py-to-exe ile Python Dosyalarını EXE'ye Dönüştürme yöntemini kullanarak:

  • Terminalden auto-py-to-exe komutunu çalıştırın.
  • Script dosyanızı seçip One File (Tek Dosya) ve Window Based (Konsolsuz) seçeneklerini işaretleyin.
  • Üretilen .exe dosyasını çift tıklayan her personel, anında klasöründe biçimlendirilmiş taze Excel kalite raporunu görecektir.

Kaynaklar ve Referanslar

Bu makale hazırlanırken aşağıdaki kaynaklardan ve resmi teknik dökümantasyonlardan faydalanılmıştır:

Yukarı Çık