diff --git a/CRM/Applications.py b/CRM/Applications.py new file mode 100644 index 0000000..eead662 --- /dev/null +++ b/CRM/Applications.py @@ -0,0 +1,209 @@ +import sys +import os +import pandas as pd +from PyQt6.QtWidgets import QApplication, QHeaderView, QTableWidgetItem +from PyQt6.uic import loadUi +from PyQt6.QtCore import Qt +from main import BaseWindow + +# Klasör yolları +BASE_DIR = os.path.dirname(__file__) +UI_DIR = os.path.join(BASE_DIR, "UI_s") +EXCEL_DIR = os.path.join(BASE_DIR, "Excels") + + +class ApplicationsWindow(BaseWindow): + def __init__(self, role="admin"): + super().__init__() + self.role = role + loadUi(os.path.join(UI_DIR, "Applications.ui"), self) + + # Excel başlıkları ve UI başlıkları artık aynı + self.table_columns = [ + "DATE", + "FULL NAME", + "E-MAIL", + "PHONE NUMBER", + "POSTAL CODE", + "PROVINCE", + "CURRENT STATUS" + ] + + self.setWindowTitle("Applications") + self.setFixedSize(1000, 600) + self.move_to_last_position() + + header = self.tableWidget.horizontalHeader() + header.setSectionResizeMode(QHeaderView.ResizeMode.Fixed) + column_widths = [100, 200, 150, 120, 120, 200] # tablo sütun sayısına göre ayarla + for col, width in enumerate(column_widths): + self.tableWidget.setColumnWidth(col, width) + + # Excel dosyalarını yükle + self.applications_file = os.path.join(EXCEL_DIR, "Basvurular.xlsx") + self.vit1_file = os.path.join(EXCEL_DIR, "VIT1.xlsx") + self.vit2_file = os.path.join(EXCEL_DIR, "VIT2.xlsx") + + self.df = pd.read_excel(self.applications_file) if os.path.exists(self.applications_file) else pd.DataFrame() + self.vit1_df = pd.read_excel(self.vit1_file) if os.path.exists(self.vit1_file) else pd.DataFrame() + self.vit2_df = pd.read_excel(self.vit2_file) if os.path.exists(self.vit2_file) else pd.DataFrame() + + # Butonlara fonksiyon bağla + self.pushButton_SEARCH.clicked.connect(self.search_applications) + self.lineEdit.textChanged.connect(self.search_applications) # CANLI ARAMA + self.pushButton_ALL_APPLICATIONS.clicked.connect(self.clear_search_input) + self.pushButton_ALL_APPLICATIONS.clicked.connect(self.load_all_applications) + self.pushButton_DEFINED_MENTOR_MEETING.clicked.connect(self.clear_search_input) + self.pushButton_DEFINED_MENTOR_MEETING.clicked.connect(self.show_defined_mentor) + self.pushButton_UNDEFINED_MENTOR_MEETING.clicked.connect(self.clear_search_input) + self.pushButton_UNDEFINED_MENTOR_MEETING.clicked.connect(self.show_undefined_mentor) + self.pushButton_DUPLICATE_REGISTRATION.clicked.connect(self.clear_search_input) + self.pushButton_DUPLICATE_REGISTRATION.clicked.connect(self.show_duplicates) + self.pushButton_PREVIOUS_VIT_CHECK.clicked.connect(self.clear_search_input) + self.pushButton_PREVIOUS_VIT_CHECK.clicked.connect(self.show_previous_vit) + self.pushButton_DIFFERENT_REGISTRATION.clicked.connect(self.clear_search_input) + self.pushButton_DIFFERENT_REGISTRATION.clicked.connect(self.show_different) + self.pushButton_APPLICATION_FILTERING.clicked.connect(self.clear_search_input) + self.pushButton_APPLICATION_FILTERING.clicked.connect(self.filter_applications) + self.pushButton_RETURN_REFERENCE_MENU.clicked.connect(self.return_to_menu) + + # ---------------- Fonksiyonlar ---------------- # + def clear_search_input(self): + self.lineEdit.clear() #Herhangi bir butona basildiginda onceki yapilan arama silinsin + + def display_data(self, df): + """DataFrame'i tabloya yazdır — artık UI başlıkları Excel başlıkları ile aynı.""" + try: + self.tableWidget.clearContents() + self.tableWidget.setRowCount(0) + + if df is None or df.empty: + print("Gösterilecek kayıt yok veya DataFrame boş.") + return + + display_df = df.copy() + for col in self.table_columns: + if col not in display_df.columns: + display_df[col] = "" + display_df = display_df.reset_index(drop=True) + + self.tableWidget.setRowCount(len(display_df)) + self.tableWidget.setColumnCount(len(self.table_columns)) + self.tableWidget.setHorizontalHeaderLabels(self.table_columns) + + for row_idx, row in display_df.iterrows(): + for col_idx, col_name in enumerate(self.table_columns): + value = row[col_name] if col_name in row else "" + item = QTableWidgetItem(str(value)) + item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self.tableWidget.setItem(row_idx, col_idx, item) + + print(f"{len(display_df)} kayıt tabloya yüklendi.\n") + + except Exception as e: + print(f"display_data() Hatası: {e}") + + def search_applications(self): + """LineEdit içindeki metin ile FULL NAME araması.""" + try: + search_text = self.lineEdit.text().strip().lower() + print("Arama metni:", search_text) + + if 'FULL NAME' not in self.df.columns: + print("'FULL NAME' sütunu bulunamadı.") + return + + if not search_text: + self.display_data(self.df) + return + + df_clean = self.df.copy() + df_clean['FULL NAME'] = df_clean['FULL NAME'].astype(str).str.lower().str.strip() + mask = df_clean['FULL NAME'].apply(lambda x: search_text in x) + filtered_df = df_clean[mask].reset_index(drop=True) + + print("Arama sonucu:", filtered_df[['FULL NAME']].to_string(index=False)) + self.display_data(filtered_df) + + + except Exception as e: + print(f"Search Error: {e}") + + def load_all_applications(self): + print(f"Toplam kayıt sayısı: {len(self.df)}") + self.display_data(self.df) + print("Tüm başvurular görüntülendi.\n") + + def show_defined_mentor(self): + if 'MENTOR MEETING' in self.df.columns: + filtered_df = self.df[self.df['MENTOR MEETING'] == 'OK'] + print(f"Mentoru atanmış adaylar filtrelendi: {len(filtered_df)} kayıt bulundu.") + self.display_data(filtered_df) + + def show_undefined_mentor(self): + if 'MENTOR MEETING' in self.df.columns: + filtered_df = self.df[self.df['MENTOR MEETING'] == 'ATANMADI'] + print(f"Mentoru atanmamış adaylar filtrelendi: {len(filtered_df)} kayıt bulundu.") + self.display_data(filtered_df) + + def show_duplicates(self): + if all(col in self.df.columns for col in ['FULL NAME', 'E-MAIL']): + duplicates = self.df[self.df.duplicated(subset=['FULL NAME', 'E-MAIL'], keep=False)] + print(f"Mükerrer kayıtlar bulundu: {len(duplicates)}") + self.display_data(duplicates) + + def filter_applications(self): + """Tekil kayıtları göster (FULL NAME + E-MAIL).""" + if all(col in self.df.columns for col in ['FULL NAME', 'E-MAIL']): + filtered = self.df.drop_duplicates(subset=['FULL NAME', 'E-MAIL'], keep='first') + self.display_data(filtered) + print("Tekil kayıtlar başarıyla listelendi.\n") + + def show_previous_vit(self): + """VIT1 veya VIT2 ile ortak adayları göster.""" + if self.vit1_df.empty and self.vit2_df.empty: + print("VIT1 ve VIT2 dosyaları bulunamadı.") + self.tableWidget.setRowCount(0) + return + + vit_all = pd.concat([self.vit1_df, self.vit2_df], ignore_index=True) + + # Sadece FULL NAME ve E-MAIL ile merge yap, orijinal df’den diğer sütunları al + common_keys = ['FULL NAME', 'E-MAIL'] + merged = self.df.merge(vit_all[common_keys], how='inner', on=common_keys) + print(f"VIT1/VIT2 ile ortak kayıtlar bulundu: {len(merged)}") + self.display_data(merged) + + + def show_different(self): + """VIT1 ve VIT2’de olmayan adayları göster.""" + if self.vit1_df.empty and self.vit2_df.empty: + print("VIT1 ve VIT2 dosyaları bulunamadı.") + self.tableWidget.setRowCount(0) + return + + vit_all = pd.concat([self.vit1_df, self.vit2_df], ignore_index=True) + keys = ['FULL NAME', 'E-MAIL'] + different_keys = self.df.merge(vit_all[keys], how='left', on=keys, indicator=True) + different = self.df[different_keys['_merge'] == 'left_only'] + print(f"VIT1/VIT2’de olmayan adaylar: {len(different)}") + self.display_data(different) + + + def return_to_menu(self): + from main import PreferenceAdminMenu, PreferenceMenu + if self.role.lower() == "admin": + self.pref_menu = PreferenceAdminMenu(role=self.role) + else: + self.pref_menu = PreferenceMenu(role=self.role) + self.pref_menu.show() + self.close() + + +# ----------------- Main ----------------- # +if __name__ == "__main__": + app = QApplication(sys.argv) + window = ApplicationsWindow(role="admin") + window.show() + sys.exit(app.exec()) + diff --git a/CRM/Excels/Basvurular.xlsx b/CRM/Excels/Basvurular.xlsx new file mode 100644 index 0000000..4c11b52 Binary files /dev/null and b/CRM/Excels/Basvurular.xlsx differ diff --git a/CRM/Excels/Event.ods b/CRM/Excels/Event.ods new file mode 100644 index 0000000..dbdb80b Binary files /dev/null and b/CRM/Excels/Event.ods differ diff --git a/CRM/Excels/Event.xlsx b/CRM/Excels/Event.xlsx new file mode 100644 index 0000000..0d252ea Binary files /dev/null and b/CRM/Excels/Event.xlsx differ diff --git a/CRM/Excels/FullSheets.xlsx b/CRM/Excels/FullSheets.xlsx new file mode 100644 index 0000000..c792df5 Binary files /dev/null and b/CRM/Excels/FullSheets.xlsx differ diff --git a/CRM/Excels/Interviews.xlsx b/CRM/Excels/Interviews.xlsx new file mode 100644 index 0000000..5494813 Binary files /dev/null and b/CRM/Excels/Interviews.xlsx differ diff --git a/CRM/Excels/Mentor.xlsx b/CRM/Excels/Mentor.xlsx new file mode 100644 index 0000000..021c357 Binary files /dev/null and b/CRM/Excels/Mentor.xlsx differ diff --git a/CRM/Excels/Mulakatlar.xlsx b/CRM/Excels/Mulakatlar.xlsx new file mode 100644 index 0000000..5494813 Binary files /dev/null and b/CRM/Excels/Mulakatlar.xlsx differ diff --git a/CRM/Excels/VIT1.xlsx b/CRM/Excels/VIT1.xlsx new file mode 100644 index 0000000..4211d0f Binary files /dev/null and b/CRM/Excels/VIT1.xlsx differ diff --git a/CRM/Excels/VIT2.xlsx b/CRM/Excels/VIT2.xlsx new file mode 100644 index 0000000..c7077d9 Binary files /dev/null and b/CRM/Excels/VIT2.xlsx differ diff --git a/CRM/Excels/users.xlsx b/CRM/Excels/users.xlsx new file mode 100644 index 0000000..d25043f Binary files /dev/null and b/CRM/Excels/users.xlsx differ diff --git a/CRM/UI_s/Admin_Menu.ui b/CRM/UI_s/Admin_Menu.ui new file mode 100644 index 0000000..88065ce --- /dev/null +++ b/CRM/UI_s/Admin_Menu.ui @@ -0,0 +1,289 @@ + + + Form + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Nirmala UI + + + + Admin Menu + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255));} + + + + + 10 + 20 + 981 + 61 + + + + + Nirmala UI + 30 + 75 + true + + + + color: rgb(214, 30, 32); + + + ADMIN MENU + + + Qt::AlignCenter + + + + + + 710 + 100 + 201 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + SEND E-MAIL + + + + + + 90 + 100 + 451 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + EVENT REGISTRATION + + + + + + 90 + 500 + 461 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + RETURN TO ADMIN PREFERENCE MENU + + + + + + 710 + 500 + 201 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + EXIT + + + + + + 90 + 190 + 821 + 291 + + + + background-color:rgb(255, 255, 255) + + + true + + + 194 + + + false + + + true + + + false + + + false + + + 28 + + + true + + + 23 + + + false + + + false + + + + Event Name + + + + + Start Time + + + + + Participant Email + + + + + Organizer Email + + + + + + + + + diff --git a/CRM/UI_s/Applications.ui b/CRM/UI_s/Applications.ui new file mode 100644 index 0000000..a0cdb3f --- /dev/null +++ b/CRM/UI_s/Applications.ui @@ -0,0 +1,488 @@ + + + Form + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Nirmala UI + + + + Applications + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255));} + + + + + 10 + 20 + 981 + 61 + + + + + Nirmala UI + 30 + 75 + true + + + + color: rgb(214, 30, 32); + + + APPLICATIONS + + + Qt::AlignCenter + + + + + + 70 + 120 + 101 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + SEARCH + + + + + + 660 + 60 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + RETURN PREFERENCE MENU + + + + + + 70 + 180 + 301 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + DEFINED MENTOR MEETING + + + + + + 390 + 240 + 251 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + ALL APPLICATIONS + + + + + + 180 + 120 + 461 + 51 + + + + + 15 + true + + + + border-style:solid; +border-width:3px; +border-radius:20px; +border-color: rgb(218, 30, 60); +color: rgb(104, 104, 104); +background-color: rgb(255, 255, 255); +border-color: rgb(220, 63, 65); + + + Enter the text you want to search for here + + + + + + 660 + 180 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + DIFFERENT REGISTRATION + + + + + + 70 + 240 + 301 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + UNDEFINED MENTOR MEETING + + + + + + 660 + 240 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + DUPLICATE REGISTRATION + + + + + + 390 + 180 + 251 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + Qt::LeftToRight + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + PREVIOUS VIT CHECK + + + + + + 660 + 120 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + APPLICATION FILTERING + + + + + + 70 + 310 + 861 + 261 + + + + background-color: rgb(255, 255, 255); + + + 136 + + + true + + + + DATE + + + + + FULL NAME + + + + + E-MAIL + + + + + PHONE NUMBER + + + + + POSTAL CODE + + + + + PROVINCE + + + + + CURRENT STATUS + + + + + + + + + diff --git a/CRM/UI_s/Interviews.ui b/CRM/UI_s/Interviews.ui new file mode 100644 index 0000000..4af1679 --- /dev/null +++ b/CRM/UI_s/Interviews.ui @@ -0,0 +1,383 @@ + + + Form + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Nirmala UI + + + + Interviews + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255));} + + + + + 10 + 20 + 981 + 61 + + + + + Nirmala UI + 30 + 75 + true + + + + color: rgb(214, 30, 32); + + + INTERVIEWS + + + Qt::AlignCenter + + + + + + 70 + 120 + 101 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + SEARCH + + + + + + 660 + 120 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + RETURN PREFERENCE MENU + + + + + + 70 + 190 + 301 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + SUBMITTED PROJECTS + + + + + + 180 + 120 + 461 + 51 + + + + + 15 + true + + + + Qt::ClickFocus + + + border-style:solid; +border-width:3px; +border-radius:20px; + +color: rgb(104, 104, 104); +background-color: rgb(255, 255, 255); +border-color: rgb(220, 63, 65); + + + Enter the text you want to search for here + + + + + + 660 + 190 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + EXIT + + + + + + 390 + 190 + 251 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + Qt::LeftToRight + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + RECEIVED PROJECTS + + + + + + 70 + 270 + 861 + 281 + + + + background-color:rgb(255, 255, 255) + + + 283 + + + true + + + + Full Name + + + + Calibri + 9 + 75 + true + + + + + 255 + 255 + 255 + + + + + + 255 + 255 + 255 + + + + + + + Submission Date + + + + Calibri + 9 + 75 + true + + + + + 255 + 255 + 255 + + + + + + Delivery Date + + + + Calibri + 9 + 75 + true + + + + + + 255 + 255 + 255 + + + + + + + + + + + diff --git a/CRM/UI_s/Login_Window.ui b/CRM/UI_s/Login_Window.ui new file mode 100644 index 0000000..7e4cf60 --- /dev/null +++ b/CRM/UI_s/Login_Window.ui @@ -0,0 +1,272 @@ + + + Form + + + true + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Modern + 15 + + + + Login Window + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + false + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255));} + + + + + 330 + 250 + 351 + 51 + + + + + Nirmala UI + 15 + true + + + + Qt::ClickFocus + + + Qt::LeftToRight + + + border-style:solid; +border-width:3px; +border-radius:20px; +border-color: rgb(218, 30, 60); +color: rgb(104, 104, 104); +background-color: rgb(255, 255, 255); +border-color: rgb(220, 63, 65); + + + Qt::ImhNone + + + + + + Qt::AlignCenter + + + false + + + Enter your username + + + + + true + + + + 330 + 320 + 351 + 51 + + + + + Nirmala UI + 15 + true + + + + Qt::ClickFocus + + + border-style:solid; +border-width:3px; +border-radius:20px; +border-color: rgb(218, 30, 60); +color: rgb(104, 104, 104); +background-color: rgb(255, 255, 255); +border-color: rgb(220, 63, 65); + + + QLineEdit::Password + + + Qt::AlignCenter + + + Enter your password + + + + + + 530 + 420 + 171 + 71 + + + + + Nirmala UI + 20 + 75 + true + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + EXIT + + + + + true + + + + 310 + 420 + 171 + 71 + + + + + Nirmala UI + 20 + 75 + true + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + LOGIN + + + false + + + + + + 10 + 160 + 981 + 51 + + + + + Nirmala UI + 32 + 75 + true + false + + + + false + + + color: rgb(214, 30, 32); + + + CRM PROJECT + + + Qt::AlignCenter + + + + + + 280 + 40 + 431 + 111 + + + + image: url(:/logo/logo_butun.png); + + + + + + + + + + + diff --git a/CRM/UI_s/Mentor_Meeting_Page.ui b/CRM/UI_s/Mentor_Meeting_Page.ui new file mode 100644 index 0000000..8aa5a32 --- /dev/null +++ b/CRM/UI_s/Mentor_Meeting_Page.ui @@ -0,0 +1,382 @@ + + + Form + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Nirmala UI + + + + Mentor Meeting Page + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255));} + + + + + 10 + 20 + 981 + 61 + + + + + Nirmala UI + 30 + 75 + true + + + + color: rgb(214, 30, 32); + + + MENTOR MEETING PAGE + + + Qt::AlignCenter + + + + + + 70 + 120 + 141 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + SEARCH + + + + + + 670 + 120 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + RETURN PREFERENCE MENU + + + + + + 70 + 180 + 141 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + ALL MEETINGS + + + + + + 230 + 120 + 421 + 51 + + + + + 15 + true + + + + border-style:solid; +border-width:3px; +border-radius:20px; +border-color: rgb(218, 30, 60); +color: rgb(104, 104, 104); +background-color: rgb(255, 255, 255); +border-color: rgb(220, 63, 65); + + + Enter the text you want to search for here + + + + + + 670 + 180 + 271 + 51 + + + + + Nirmala UI + 15 + 50 + false + + + + Qt::LeftToRight + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + EXIT + + + + + + 70 + 250 + 871 + 321 + + + + background-color:rgb(255, 255, 255) + + + false + + + 144 + + + 54 + + + true + + + + Meeting Date + + + + + Applicant Name + + + + + Mentor Name + + + + + IT Knowledge Level + + + + + Workload Level + + + + + Comments + + + + + + + 230 + 180 + 421 + 51 + + + + QPushButton { + font-size: 16px; + font-weight: bold; + font-family: Arial; + color: black; /* Siyah yazı rengi */ + + background-color: rgb(255, 255, 255); + border-radius: 8px; /* Köşe yuvarlama */ + padding: 8px; /* Küçük padding */ + border: none; + + /* Gölgelendirme eklemek için: */ + box-shadow: 3px 3px 6px rgba(0, 0, 0, 0.3); /* Gölgenin boyutu ve rengi */ +} + +QPushButton:hover { + background-color: #c0c0c0; /* Hover durumunda biraz daha koyu gri */ + /* Hover durumunda gölgeyi değiştirmek için */ + box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5); /* Hover sırasında daha belirgin gölge */ +} + + + + + VIT projesinin tamamına katılması uygun olur + + + + + VIT projesi ilk IT eğitimi alıp ITPH a yönlendirilmesi uygun olur + + + + + VIT projesi ingilizce eğitimi alıp ITPH a yönlendirilmesi uygun olur + + + + + VIT projesi kapsamında direkt ITPH a yönlendirilmesi uygun olur. + + + + + Direkt bireysel koçluk ile işe yönlendirilmesi uygun olur + + + + + Bir sonraki VIT projesine katilmasi daha uygun olur + + + + + Başka bir sektöre yönlendirilmeli + + + + + Diger + + + + + + + + + diff --git a/CRM/UI_s/Preference_Admin_Menu.ui b/CRM/UI_s/Preference_Admin_Menu.ui new file mode 100644 index 0000000..fe52eff --- /dev/null +++ b/CRM/UI_s/Preference_Admin_Menu.ui @@ -0,0 +1,297 @@ + + + Form + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Nirmala UI + + + + Preference Admin Menu + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255)); + +} + + + + + 10 + 20 + 981 + 61 + + + + + Nirmala UI + 30 + 75 + true + + + + color: rgb(214, 30, 32); + + + PREFERENCE ADMIN MENU + + + Qt::AlignCenter + + + + + + 510 + 160 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + APPLICATIONS + + + + + + 130 + 250 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + MENTOR MEETING + + + + + + 130 + 160 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + INTERVIEWS + + + + + + 130 + 420 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + RETURN MAIN MENU + + + + + + 700 + 420 + 151 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + EXIT + + + + + + 510 + 250 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + ADMIN MENU + + + + + + + + diff --git a/CRM/UI_s/Preference_Menu.ui b/CRM/UI_s/Preference_Menu.ui new file mode 100644 index 0000000..ea09aa0 --- /dev/null +++ b/CRM/UI_s/Preference_Menu.ui @@ -0,0 +1,259 @@ + + + Form + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Nirmala UI + + + + Preference Menu + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255));} + + + + + 10 + 20 + 981 + 61 + + + + + Nirmala UI + 30 + 75 + true + + + + color: rgb(214, 30, 32); + + + PREFERENCE MENU + + + Qt::AlignCenter + + + + + + 510 + 160 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + APPLICATIONS + + + + + + 130 + 250 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + MENTOR MEETING + + + + + + 130 + 160 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + INTERVIEWS + + + + + + 130 + 420 + 341 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + RETURN MAIN MENU + + + + + + 700 + 420 + 151 + 71 + + + + + Nirmala UI + 18 + 50 + false + + + + QPushButton{ + color: rgb(214, 30, 32); + background-color: rgb(253, 253, 253); +} + +QPushButton::hover{ + background-color: rgb(226, 92, 93); + color: rgb(255, 255, 255); +} + +QPushButton::pressed{ + background-color: rgb(216, 37, 39); +} + + + EXIT + + + + + + + + diff --git a/CRM/UI_s/Splash_Screen.ui b/CRM/UI_s/Splash_Screen.ui new file mode 100644 index 0000000..7a98524 --- /dev/null +++ b/CRM/UI_s/Splash_Screen.ui @@ -0,0 +1,108 @@ + + + Form + + + true + + + + 0 + 0 + 1000 + 600 + + + + + 0 + 0 + + + + + 1000 + 600 + + + + + 1000 + 600 + + + + + Modern + 15 + + + + Login Window + + + + :/logo/logo_icon.png:/logo/logo_icon.png + + + false + + + #Form{ +background-color: qconicalgradient(cx:0.114, cy:0.113318, angle:134.3, stop:0 rgba(214, 28, 30, 255), stop:1 rgba(255, 255, 255, 255));} + + + + + 10 + 130 + 971 + 250 + + + + image: url(:/logo/logo_butun.png); + + + + + + true + + + + + + 230 + 460 + 541 + 23 + + + + QProgressBar { + background: rgba(255, 255, 255, 0.25); /* Yarı saydam beyaz */ + border: 1px solid rgba(255, 255, 255, 0.4); + border-radius: 10px; + text-align: center; + color: rgba(255, 255, 255, 0.8); + font: bold 10pt "Segoe UI"; +} + +QProgressBar::chunk { + background-color: rgba(120, 120, 120, 0.85); /* Daha koyu gri dolum */ + border-radius: 10px; + margin: 1px; +} + + + + 24 + + + + + + + + diff --git a/CRM/UI_s/ZZZZZZ.txt b/CRM/UI_s/ZZZZZZ.txt new file mode 100644 index 0000000..6c518b9 --- /dev/null +++ b/CRM/UI_s/ZZZZZZ.txt @@ -0,0 +1,15 @@ +pyuic6 -x Splash_Screen.ui -o Splash_Screen.py + +pyuic6 -x Admin_Menu.ui -o Admin_Menu.py + +pyuic6 -x Applications.ui -o Applications.py + +pyuic6 -x Interviews.ui -o Interviews.py + +pyuic6 -x Login_Window.ui -o Login_Window.py + +pyuic6 -x Mentor_Meeting_Page.ui -o Mentor_Meeting_Page.py + +pyuic6 -x Preference_Admin_Menu.ui -o Preference_Admin_Menu.py + +pyuic6 -x Preference_Menu.ui -o Preference_Menu.py diff --git a/CRM/UI_s/logo/logo.qrc b/CRM/UI_s/logo/logo.qrc new file mode 100644 index 0000000..ac423f8 --- /dev/null +++ b/CRM/UI_s/logo/logo.qrc @@ -0,0 +1,6 @@ + + + logo_butun.png + logo_icon.png + + diff --git a/CRM/UI_s/logo/logo_butun.png b/CRM/UI_s/logo/logo_butun.png new file mode 100644 index 0000000..af86ffd Binary files /dev/null and b/CRM/UI_s/logo/logo_butun.png differ diff --git a/CRM/UI_s/logo/logo_icon.png b/CRM/UI_s/logo/logo_icon.png new file mode 100644 index 0000000..0829f07 Binary files /dev/null and b/CRM/UI_s/logo/logo_icon.png differ diff --git a/CRM/__pycache__/Login_Window.cpython-313.pyc b/CRM/__pycache__/Login_Window.cpython-313.pyc new file mode 100644 index 0000000..b8380cb Binary files /dev/null and b/CRM/__pycache__/Login_Window.cpython-313.pyc differ diff --git a/CRM/__pycache__/Splash_Screen.cpython-313.pyc b/CRM/__pycache__/Splash_Screen.cpython-313.pyc new file mode 100644 index 0000000..08dcc36 Binary files /dev/null and b/CRM/__pycache__/Splash_Screen.cpython-313.pyc differ diff --git a/CRM/__pycache__/logo_rc.cpython-313.pyc b/CRM/__pycache__/logo_rc.cpython-313.pyc new file mode 100644 index 0000000..ea66a08 Binary files /dev/null and b/CRM/__pycache__/logo_rc.cpython-313.pyc differ diff --git a/CRM/admin_menu_page.py b/CRM/admin_menu_page.py new file mode 100644 index 0000000..a1c5514 --- /dev/null +++ b/CRM/admin_menu_page.py @@ -0,0 +1,211 @@ + +import os +import sys +import smtplib +from email.mime.text import MIMEText +import pandas as pd + +from PyQt6.uic import loadUi +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import ( + QApplication, + QMessageBox, + QTableWidgetItem +) + +try: + from main import BaseWindow +except Exception: + from PyQt6.QtWidgets import QWidget as BaseWindow + + +BASE_DIR = os.path.dirname(__file__) +UI_DIR = os.path.join(BASE_DIR, "UI_s") +EXCEL_DIR = os.path.join(BASE_DIR, "Excels") # Event.xlsx burada olacak + + +class AdminMenuWindow(BaseWindow): + def __init__(self, role="admin"): + super().__init__() + + ui_path = os.path.join(UI_DIR, "Admin_Menu.ui") + + try: + loadUi(ui_path, self) + except Exception as e: + QMessageBox.critical( + self, "UI Load Error", + f"Failed to load UI:\n{ui_path}\n\n{e}" + ) + raise + + self.role = role + self.setWindowTitle("Admin Menu") + self.setFixedSize(1000, 600) + self.setWindowFlag(Qt.WindowType.FramelessWindowHint) + + if hasattr(self, "move_to_last_position"): + self.move_to_last_position() + + # --- Button connections --- + self.pushButton_EVENT_REGISTRATION.clicked.connect(self.register_event) + self.pushButton_SEND_EMAIL.clicked.connect(self.send_email) + self.pushButton_Return_TO_ADMIN_PREFERENCE_menu.clicked.connect(self.return_to_admin_pref_menu) + self.pushButton_Exit.clicked.connect(self.close) + + self.tableWidget.setColumnCount(4) + + + + # 1) Excel (Event.xlsx) → Tabloya yükleme + + def register_event(self): + excel_path = os.path.join(EXCEL_DIR, "Event.xlsx") + + if not os.path.exists(excel_path): + QMessageBox.warning(self, "Missing File", f"Event.xlsx not found:\n{excel_path}") + return + + try: + df = pd.read_excel(excel_path) + + required_columns = [ + "EVENT NAME", + "START TIME", + "PARTICIPANT E-MAIL", + "ORGANIZER E-MAIL" + ] + + for col in required_columns: + if col not in df.columns: + QMessageBox.critical( + self, + "Column Error", + f"Missing column in Event.xlsx:\n'{col}'" + ) + return + + self.tableWidget.setRowCount(0) + + for row_idx, row in df.iterrows(): + self.tableWidget.insertRow(row_idx) + self.tableWidget.setItem(row_idx, 0, QTableWidgetItem(str(row["EVENT NAME"]))) + self.tableWidget.setItem(row_idx, 1, QTableWidgetItem(str(row["START TIME"]))) + self.tableWidget.setItem(row_idx, 2, QTableWidgetItem(str(row["PARTICIPANT E-MAIL"]))) + self.tableWidget.setItem(row_idx, 3, QTableWidgetItem(str(row["ORGANIZER E-MAIL"]))) + + except Exception as e: + QMessageBox.critical(self, "Excel Error", f"Failed to read Event.xlsx:\n{e}") + + + # 2-Gerçek Mail Gönderme (Gmail App Password gerekli) + + def send_email(self): + rows = self.tableWidget.rowCount() + + if rows == 0: + QMessageBox.warning(self, "No Data", "No events loaded.") + return + + SMTP_SERVER = "smtp.gmail.com" + SMTP_PORT = 587 + + # BURAYI KENDİ GMAIL HESABINLA DOLDURACAKSIN + SENDER_EMAIL = "your_email@gmail.com" + SENDER_PASSWORD = "your_app_password" # Gmail App Password + + if "your_email" in SENDER_EMAIL: + QMessageBox.warning( + self, + "Setup Needed", + "Please set your Gmail address and App Password in the code." + ) + return + + try: + server = smtplib.SMTP(SMTP_SERVER, SMTP_PORT, timeout=20) + server.starttls() + server.login(SENDER_EMAIL, SENDER_PASSWORD) + + sent_count = 0 + + for r in range(rows): + event_name = self._safe(r, 0) + participant = self._safe(r, 2) + organizer = self._safe(r, 3) + + emails = self._split_emails(participant) + self._split_emails(organizer) + + if not emails: + continue + + msg = MIMEText( + f"Hello,\n\nThis is a reminder for the event:\n\n" + f"{event_name}\n\nBest regards,\nCRM System" + ) + msg["Subject"] = f"Event Reminder – {event_name}" + msg["From"] = SENDER_EMAIL + + for email in emails: + msg["To"] = email + server.sendmail(SENDER_EMAIL, email, msg.as_string()) + sent_count += 1 + + server.quit() + + QMessageBox.information(self, "Success", f"Emails sent: {sent_count}") + + except smtplib.SMTPAuthenticationError: + QMessageBox.critical( + self, + "Authentication Error", + "Gmail blocked the login.\n" + "You MUST use a Gmail App Password:\n" + "Google Account → Security → App Passwords." + ) + except Exception as e: + QMessageBox.critical(self, "Email Error", str(e)) + + + def _safe(self, r, c): + item = self.tableWidget.item(r, c) + return item.text().strip() if item else "" + + def _split_emails(self, text): + if not text: + return [] + parts = [p.strip() for p in text.replace(";", ",").split(",")] + return [p for p in parts if "@" in p] + + + # RETURN — Admin Preference Menu’ye geri dön + def return_to_admin_pref_menu(self): + # 1) Normal durumda: proje main.py'den çalışınca + try: + from main import PreferenceAdminMenu + except ImportError: + # 2) Python main.py'yi __main__ olarak çalıştırdıysa burası devreye girer + try: + from __main__ import PreferenceAdminMenu + except ImportError: + QMessageBox.warning( + self, + "Return Error", + "Cannot return to previous menu because main module was not found." + ) + return + self.new_window = PreferenceAdminMenu(role=self.role) # REFERANS ÖNEMLİ + self.new_window.show() + self.close() + + + + +if __name__ == "__main__": + app = QApplication(sys.argv) + w = AdminMenuWindow() + w.show() + sys.exit(app.exec()) + + + diff --git a/CRM/applications_page.py b/CRM/applications_page.py new file mode 100644 index 0000000..e89c725 --- /dev/null +++ b/CRM/applications_page.py @@ -0,0 +1,36 @@ +import os +from PyQt6.uic import loadUi +from PyQt6.QtCore import Qt +from main import BaseWindow + +BASE_DIR = os.path.dirname(__file__) +UI_DIR = os.path.join(BASE_DIR, "UI_s") + +class ApplicationsWindow(BaseWindow): + def __init__(self, role="admin"): + super().__init__() + self.role = role + loadUi(os.path.join(UI_DIR, "Applications.ui"), self) + self.setWindowTitle("Applications") + self.setFixedSize(1000, 600) + self.move_to_last_position() + + self.pushButton_RETURN_REFERENCE_MENU.clicked.connect(self.return_to_menu) + self.pushButton_SEARCH.clicked.connect(self.search_action) + self.pushButton_ALL_APPLICATIONS.clicked.connect(self.show_all_applications) + + def return_to_menu(self): + from main import PreferenceAdminMenu, PreferenceMenu + if self.role.lower() == "admin": + self.pref_menu = PreferenceAdminMenu(role=self.role) + else: + self.pref_menu = PreferenceMenu(role=self.role) + self.pref_menu.show() + self.close() + + def search_action(self): + text = self.lineEdit.text().strip() + print(f"Arama yapılıyor: {text}") + + def show_all_applications(self): + print("Tüm başvurular listeleniyor...") \ No newline at end of file diff --git a/CRM/interviews_page.py b/CRM/interviews_page.py new file mode 100644 index 0000000..b6f6b9d --- /dev/null +++ b/CRM/interviews_page.py @@ -0,0 +1,190 @@ +# interview_page +import os +import pandas as pd +from PyQt6.uic import loadUi +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QMessageBox, QTableWidgetItem, QApplication +from main import BaseWindow +from PyQt6.QtWidgets import QHeaderView + + +BASE_DIR = os.path.dirname(__file__) +UI_DIR = os.path.join(BASE_DIR, "UI_s") +EXCEL_PATH = os.path.join(BASE_DIR, "Excels", "Interviews.xlsx") + + +class InterviewsWindow(BaseWindow): + def __init__(self, role="admin"): + super().__init__() + self.role = role + loadUi(os.path.join(UI_DIR, "Interviews.ui"), self) + self.setWindowTitle("Interviews") + self.setFixedSize(1000, 600) + self.setWindowFlag(Qt.WindowType.FramelessWindowHint) + self.move_to_last_position() + # Tablo başlıkları + self.tableWidget.setColumnCount(3) + self.tableWidget.setHorizontalHeaderLabels([ + "Full Name", "Submitted Project", "Received Project" +]) + header = self.tableWidget.horizontalHeader() + header.setStretchLastSection(True) + header.setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch) + header.setSectionResizeMode(1, QHeaderView.ResizeMode.Stretch) + header.setSectionResizeMode(2, QHeaderView.ResizeMode.Stretch) + + + # Excel yükleme ve normalize edilmiş kolon isimleri + if os.path.exists(EXCEL_PATH): + try: + self.df = pd.read_excel(EXCEL_PATH) + except Exception as e: + QMessageBox.critical(self, "Dosya Hatası", f"Excel okunamadı:\n{e}") + self.df = pd.DataFrame() + else: + QMessageBox.critical(self, "Dosya Hatası", f"Excel dosyası bulunamadı:\n{EXCEL_PATH}") + self.df = pd.DataFrame() + + + self.col_map = {} + if not self.df.empty: + for c in self.df.columns: + self.col_map[c.strip().lower()] = c # map: lowercase -> gerçek sütun adı + + # Olası sütun isimlerini tespit ediliyor (Türkçe ve İngilizce olasılıkları) + self.name_col = self._pick_column(["full name", "adınız soyadınız", "adınız soyadınız", "ad soyad", "adiniz soyadiniz"]) + self.submitted_col = self._pick_column(["submitted project", "proje gonderilis tarihi", "proje gönderiliş tarihi", "project submitted", "submitted"]) + self.received_col = self._pick_column(["received project", "projenin gelis tarihi", "proje gelis tarihi", "received"]) + + # Bağlantılar + self.pushButton_Return_REFERENCE_menu.clicked.connect(self.return_to_menu) + self.pushButton_EXIT.clicked.connect(self.close) + self.pushButton_SEARCH.clicked.connect(self.search_action) + self.pushButton_SUBMITTED_PROJECTS.clicked.connect(self.show_submitted_projects) + self.pushButton_RECEIVED_PROJECTS.clicked.connect(self.show_received_projects) + + + + def _pick_column(self, candidates): + """Verilen anahtar listesine göre ilk eşleşen gerçek sütun adını döndürür.""" + if self.df.empty: + return None + lower_cols = [c.lower().strip() for c in self.df.columns] + for cand in candidates: + cand_low = cand.lower().strip() + for i, lc in enumerate(lower_cols): + # Tam veya içinde eşleşme kabul edelim + if cand_low == lc or cand_low in lc or lc in cand_low: + return self.df.columns[i] + return None + + def fill_table(self, data: pd.DataFrame): + # verilen DataFrame'i TableWidget'e yazmak + self.tableWidget.setRowCount(0) + for row_idx, row in data.reset_index(drop=True).iterrows(): + self.tableWidget.insertRow(row_idx) + # Eğer sütun yoksa boş string koy + name_val = row.get(self.name_col, "") if self.name_col in row.index else row.get("Adınız Soyadınız", "") + sub_val = row.get(self.submitted_col, "") if self.submitted_col in row.index else row.get("Proje gonderilis tarihi", "") + rec_val = row.get(self.received_col, "") if self.received_col in row.index else row.get("Projenin gelis tarihi", "") + + self.tableWidget.setItem(row_idx, 0, QTableWidgetItem("" if pd.isna(name_val) else str(name_val))) + self.tableWidget.setItem(row_idx, 1, QTableWidgetItem("" if pd.isna(sub_val) else str(sub_val))) + self.tableWidget.setItem(row_idx, 2, QTableWidgetItem("" if pd.isna(rec_val) else str(rec_val))) + + + def search_action(self): + """NAME sütununda BAŞLANGIÇ (startswith) araması yapar, case-insensitive.""" + if self.name_col is None: + QMessageBox.critical(self, "Error", "Name column could not be found in the Excel file.") + return + text = self.lineEdit.text().strip() + if text == "": + QMessageBox.information(self, "INFO", "Please enter text to search.") + return + + # Case-insensitive, baştan eşleşme. NaN güvenli. + series = self.df[self.name_col].astype(str).str.strip() + mask = series.str.lower().str.startswith(text.lower(), na=False) + filtered = self.df[mask] + if filtered.empty: + QMessageBox.information(self, "No Results ", f"No names starting with '{text}' were found.") + + else: + self.fill_table(filtered) + + def keyPressEvent(self, event): + if event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter): + self.search_action() + + + + + def show_submitted_projects(self): + # """Displays all candidates who have SUBMITTED a project.""" + col = self.submitted_col + if col is None: + for c in self.df.columns: + low = c.strip().lower() + if "submitted" in low or ("send" in low) or ("gonder" in low): + col = c + break + + if col is None: + QMessageBox.critical(self, "Error", "'Submitted Project' column not found in the Excel file.") + return + + mask = self.df[col].notna() & (self.df[col].astype(str).str.strip() != "") + submitted = self.df[mask] + + if submitted.empty: + QMessageBox.information(self, "Info", "No candidates with submitted projects found.") + else: + self.fill_table(submitted) + + + + def show_received_projects(self): + # """Displays all candidates whose projects have been RECEIVED.""" + col = self.received_col + if col is None: + for c in self.df.columns: + low = c.strip().lower() + if "received" in low or "gel" in low or "delivered" in low: + col = c + break + + if col is None: + QMessageBox.critical(self, "Error", "'Received Project' column not found in the Excel file.") + return + + mask = self.df[col].notna() & (self.df[col].astype(str).str.strip() != "") + received = self.df[mask] + + if received.empty: + QMessageBox.information(self, "Info", "No candidates with received projects found.") + else: + self.fill_table(received) + + + + + def return_to_menu(self): + from main import PreferenceAdminMenu, PreferenceMenu + if self.role.lower() == "admin": + self.pref_menu = PreferenceAdminMenu(role=self.role) + else: + self.pref_menu = PreferenceMenu(role=self.role) + self.pref_menu.show() + self.close() + + +# test +if __name__ == "__main__": + import sys + app = QApplication(sys.argv) + w = InterviewsWindow(role="admin") + w.show() + sys.exit(app.exec()) + + diff --git a/CRM/main.py b/CRM/main.py new file mode 100644 index 0000000..3563596 --- /dev/null +++ b/CRM/main.py @@ -0,0 +1,235 @@ +import sys +import os +import pandas as pd +from PyQt6.QtWidgets import QApplication, QWidget, QMainWindow, QLabel +from PyQt6.QtCore import QTimer, Qt +from PyQt6.QtGui import QPixmap, QIcon +from PyQt6.uic import loadUi + +# Klasör yolları +BASE_DIR = os.path.dirname(__file__) +UI_DIR = os.path.join(BASE_DIR, "UI_s") +IMG_DIR = os.path.join(UI_DIR, "logo") +EXCEL_DIR = os.path.join(BASE_DIR, "Excels") + +# ==== GLOBAL DEĞİŞKEN ==== # +last_window_pos = None # Son pencere pozisyonunu saklamak için + +# ==== BASE WINDOW ==== # +class BaseWindow(QWidget): + def __init__(self): + super().__init__() + self.oldPos = None + + def mousePressEvent(self, event): + if event.button() == Qt.MouseButton.LeftButton: + self.oldPos = event.globalPosition().toPoint() + + def mouseMoveEvent(self, event): + import main # global değişkeni güncel tutmak için if event.buttons() == Qt.MouseButton.LeftButton: + delta = event.globalPosition().toPoint() - self.oldPos + self.move(self.x() + delta.x(), self.y() + delta.y()) + self.oldPos = event.globalPosition().toPoint() + main.last_window_pos = self.pos() + + def move_to_last_position(self): + import main + if main.last_window_pos: + self.move(main.last_window_pos) + else: + # İlk sefer için, mevcut konumu kaydet + main.last_window_pos = self.pos() + + self.setWindowIcon(QIcon("UI_s/logo/logo_icon.png")) + + +class SplashScreen(BaseWindow): + def __init__(self): + super().__init__() + splash_ui_path = os.path.join(UI_DIR, "Splash_Screen.ui") + loadUi(splash_ui_path, self) + self.setWindowTitle("CRM Splash Screen") + self.setFixedSize(1000, 600) + self.move_to_last_position() + + # Logo yükleme + logo_path = os.path.join(IMG_DIR, "logo_butun.png") + if os.path.exists(logo_path): + self.label_logo.setPixmap(QPixmap(logo_path)) + self.label_logo.setScaledContents(True) + + + + self.counter = 0 + self.timer = QTimer() + self.timer.timeout.connect(self.update_progress) + self.timer.start(10) + + def update_progress(self): + self.counter += 1 + self.progressBar.setValue(self.counter) + if self.counter >= 100: + self.timer.stop() + self.show_login() + + def show_login(self): + self.login_window = LoginWindow() + self.login_window.show() + self.close() + + +class LoginWindow(BaseWindow): + def __init__(self): + super().__init__() + login_ui_path = os.path.join(UI_DIR, "Login_Window.ui") + loadUi(login_ui_path, self) + self.setWindowTitle("CRM Login") + self.setFixedSize(1000, 600) + self.move_to_last_position() + + # Excel'den kullanıcıları oku + users_file = os.path.join(EXCEL_DIR, "users.xlsx") + if os.path.exists(users_file): + self.users_df = pd.read_excel(users_file) + else: + print("⚠️ Kullanıcı dosyası bulunamadı:", users_file) + self.users_df = pd.DataFrame(columns=["username", "password", "role"]) + + # Logo yükleme + logo_path = os.path.join(IMG_DIR, "logo_butun.png") + if os.path.exists(logo_path) and hasattr(self, "label"): + self.label.setPixmap(QPixmap(logo_path)) + self.label.setScaledContents(True) + + # Buton bağlantıları + self.pushButton_Exit.clicked.connect(self.close) + self.pushButton_Login.clicked.connect(self.login) + + def login(self): + username = self.lineEdit_username.text() + password = self.lineEdit_password.text() + + match = self.users_df[ + (self.users_df['username'] == username) & + (self.users_df['password'] == password) + ] + + if not match.empty: + role = match.iloc[0]['role'].lower() + print(f"Giriş başarılı! Rol: {role}") + if role == "admin": + self.dashboard = PreferenceAdminMenu(role=role) + else: + self.dashboard = PreferenceMenu(role=role) + self.dashboard.show() + self.close() + else: + print("Hatalı kullanıcı adı veya şifre.") + + def keyPressEvent(self, event): + if event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter): + self.login() + + +# ==== ADMIN REEFERENCE MENU ==== # +class PreferenceAdminMenu(BaseWindow): + def __init__(self, role="admin"): + super().__init__() + self.role = role + loadUi(os.path.join(UI_DIR, "Preference_Admin_Menu.ui"), self) + self.setWindowTitle("Admin Menu") + self.setFixedSize(1000, 600) + self.move_to_last_position() + + self.pushButton_INTERVIEWS.clicked.connect(self.open_interviews) + self.pushButton_APPLICATIONS.clicked.connect(self.open_applications) + self.pushButton_Mentor_Meeting.clicked.connect(self.open_mentor_meeting) + self.pushButton_ADMIN_MENU.clicked.connect(self.open_admin_settings) + self.pushButton_Return_Main_menu.clicked.connect(self.return_to_login) + self.pushButton_Exit.clicked.connect(self.close) + + def open_interviews(self): + from interviews_page import InterviewsWindow + self.interviews_window = InterviewsWindow(role=self.role) + self.interviews_window.show() + self.close() + + def open_applications(self): + from Applications import ApplicationsWindow #applications_page yerine Applications olarak düzelttim + self.app_window = ApplicationsWindow(role=self.role) + self.app_window.show() + self.close() + + def open_mentor_meeting(self): + from mentor_meeting_page import MentorMeetingWindow + self.mentor_meeting_window = MentorMeetingWindow(role=self.role) + self.mentor_meeting_window.show() + self.close() + + def open_admin_settings(self): + from admin_menu_page import AdminMenuWindow + self.admin_menu = AdminMenuWindow(role=self.role) + self.admin_menu.show() + self.close() + + def return_to_login(self): + self.login = LoginWindow() + self.login.show() + self.close() + + +# ==== USER REEFERENCE MENU ==== # +class PreferenceMenu(BaseWindow): + def __init__(self, role="user"): + super().__init__() + self.role = role + loadUi(os.path.join(UI_DIR, "Preference_Menu.ui"), self) + self.setWindowTitle("User Menu") + self.setFixedSize(1000, 600) + self.move_to_last_position() + + if hasattr(self, "pushButton_INTERVIEWS"): + self.pushButton_INTERVIEWS.clicked.connect(self.open_interviews) + if hasattr(self, "pushButton_APPLICATIONS"): + self.pushButton_APPLICATIONS.clicked.connect(self.open_applications) + if hasattr(self, "pushButton_Mentor_Meeting"): + self.pushButton_Mentor_Meeting.clicked.connect(self.open_mentor_meeting) + if hasattr(self, "pushButton_Return_Main_menu"): + self.pushButton_Return_Main_menu.clicked.connect(self.return_to_login) + if hasattr(self, "pushButton_Exit"): + self.pushButton_Exit.clicked.connect(self.close) + + def open_interviews(self): + from interviews_page import InterviewsWindow + self.interviews_window = InterviewsWindow(role=self.role) + self.interviews_window.show() + self.close() + + def open_applications(self): + from applications_page import ApplicationsWindow + self.app_window = ApplicationsWindow(role=self.role) + self.app_window.show() + self.close() + + def open_mentor_meeting(self): + from mentor_meeting_page import MentorMeetingWindow + self.mentor_meeting_window = MentorMeetingWindow(role=self.role) + self.mentor_meeting_window.show() + self.close() + + def return_to_login(self): + self.login = LoginWindow() + self.login.show() + self.close() + + +# ==== MAIN ==== # +def main(): + app = QApplication(sys.argv) + splash = SplashScreen() + splash.show() + sys.exit(app.exec()) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/CRM/mentor_meeting_page.py b/CRM/mentor_meeting_page.py new file mode 100644 index 0000000..2ac189e --- /dev/null +++ b/CRM/mentor_meeting_page.py @@ -0,0 +1,159 @@ +import os +import pandas as pd +from PyQt6.uic import loadUi +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QTableWidgetItem, QHeaderView +from main import BaseWindow + +BASE_DIR = os.path.dirname(__file__) +UI_DIR = os.path.join(BASE_DIR, "UI_s") +EXCEL_DIR = os.path.join(BASE_DIR, "Excels") + +class MentorMeetingWindow(BaseWindow): + def __init__(self, role="admin"): + super().__init__() + self.role = role + loadUi(os.path.join(UI_DIR, "Mentor_Meeting_Page.ui"), self) + self.setWindowTitle("Mentor Meeting Page") + self.setFixedSize(1000, 600) + self.move_to_last_position() + + header = self.tableWidget.horizontalHeader() + header.setSectionResizeMode(QHeaderView.ResizeMode.Fixed) + column_widths = [100, 200, 150, 120, 120, 200] # tablo sütun sayısına göre ayarla + for col, width in enumerate(column_widths): + self.tableWidget.setColumnWidth(col, width) + + # Excel dosyasını yükle + self.excel_file = os.path.join(EXCEL_DIR, "Mentor.xlsx") + if os.path.exists(self.excel_file): + df_full = pd.read_excel(self.excel_file, header=None) + + # İstenmeyen sütunları çıkar: 2., 6., 7. + # Pandas sütunları 0-index, yani 2. = 1, 6. = 5, 7. = 6 + cols_to_use = [0, 2, 3, 4, 7, 5] # 0=Interview Date, 2=Applicant Name, 3=Mentor Name, 4=IT Knowledge Level, 7=Workload Level, 5=Comments + self.df = df_full.iloc[:, cols_to_use] + self.df.columns = ["Interview Date", "Applicant Name", "Mentor Name", + "IT Knowledge Level", "Workload Level", "Comments"] + else: + self.df = pd.DataFrame(columns=["Interview Date", "Applicant Name", "Mentor Name", + "IT Knowledge Level", "Workload Level", "Comments"]) + print("Mentor Excel file not found!") + + # Buton bağlantıları + self.pushButton_Return_REFERENCE_menu.clicked.connect(self.return_to_menu) + self.pushButton_EXIT.clicked.connect(self.close) + self.pushButton_SEARCH.clicked.connect(self.search_action) + self.lineEdit.textChanged.connect(self.search_action) # CANLI ARAMA + self.pushButton_ALL_MEETINGS.clicked.connect(self.show_all_records) + self.pushButton_ALL_MEETINGS.clicked.connect(self.clear_search_input) + self.comboBox.currentTextChanged.connect(self.filter_by_comment) + self.comboBox.currentTextChanged.connect(self.clear_search_input) + + # Tablonun başlıklarını ayarla + self.tableWidget.setColumnCount(6) + self.tableWidget.setHorizontalHeaderLabels(self.df.columns) + + # Tüm kayıtları göster başlangıçta + self.show_all_records() + + def clear_search_input(self): + self.lineEdit.clear() + + def return_to_menu(self): + from main import PreferenceAdminMenu, PreferenceMenu + if self.role.lower() == "admin": + self.pref_menu = PreferenceAdminMenu(role=self.role) + else: + self.pref_menu = PreferenceMenu(role=self.role) + self.pref_menu.show() + self.close() + + def filter_by_comment(self, text): + """ComboBox seçimine göre Comments sütununu filtrele.""" + try: + if 'Comments' not in self.df.columns: + print("'Comments' sütunu bulunamadı.") + return + + if text == "" or text == "All": + # Seçim yoksa tüm veriyi göster + self.display_data(self.df) + return + + filtered_df = self.df[self.df['Comments'] == text].reset_index(drop=True) + self.display_data(filtered_df) + print(f"ComboBox filtreleme: '{text}' seçildi, {len(filtered_df)} kayıt bulundu.") + except Exception as e: + print(f"filter_by_comment Hatası: {e}") + + def show_all_records(self): + self.populate_table(self.df) + + def display_data(self, df): + """DataFrame'i Mentor Meeting tablosuna yazdırır.""" + try: + self.tableWidget.clearContents() + self.tableWidget.setRowCount(0) + + if df is None or df.empty: + print("Gösterilecek kayıt yok veya DataFrame boş.") + return + + # Tablonun sütun sayısını ayarla + self.tableWidget.setRowCount(len(df)) + self.tableWidget.setColumnCount(len(df.columns)) + self.tableWidget.setHorizontalHeaderLabels(df.columns.tolist()) + + for row_idx, row in df.iterrows(): + for col_idx, value in enumerate(row): + item = QTableWidgetItem(str(value)) + item.setTextAlignment(Qt.AlignmentFlag.AlignCenter) + self.tableWidget.setItem(row_idx, col_idx, item) + + print(f"{len(df)} kayıt tabloya yüklendi.\n") + + except Exception as e: + print(f"display_data() Hatası: {e}") + + + def search_action(self): + """Search by Applicant or Mentor Name, display all if empty""" + try: + search_text = self.lineEdit.text().strip().lower() + if not search_text: + self.show_all_records() + return + + df_clean = self.df.copy() + df_clean['Applicant Name'] = df_clean['Applicant Name'].astype(str).str.lower().str.strip() + df_clean['Mentor Name'] = df_clean['Mentor Name'].astype(str).str.lower().str.strip() + + mask = df_clean['Applicant Name'].apply(lambda x: search_text in x) | \ + df_clean['Mentor Name'].apply(lambda x: search_text in x) + + filtered_df = df_clean[mask].reset_index(drop=True) + self.populate_table(filtered_df) + + + except Exception as e: + print(f"Search Error: {e}") + + + def populate_table(self, df_to_show): + self.tableWidget.setRowCount(len(df_to_show)) + for row_idx, row in df_to_show.iterrows(): + for col_idx, value in enumerate(row): + item = QTableWidgetItem(str(value)) + self.tableWidget.setItem(row_idx, col_idx, item) + self.tableWidget.resizeColumnsToContents() + + +if __name__ == "__main__": + import sys + from PyQt6.QtWidgets import QApplication + + app = QApplication(sys.argv) + window = MentorMeetingWindow(role="admin") + window.show() + sys.exit(app.exec()) diff --git a/interviews_page.py b/interviews_page.py new file mode 100644 index 0000000..dace925 --- /dev/null +++ b/interviews_page.py @@ -0,0 +1,163 @@ + +import os +import pandas as pd +from PyQt6.uic import loadUi +from PyQt6.QtCore import Qt +from PyQt6.QtWidgets import QMessageBox, QTableWidgetItem, QApplication +from main import BaseWindow + +BASE_DIR = os.path.dirname(__file__) +UI_DIR = os.path.join(BASE_DIR, "UI_s") +EXCEL_PATH = os.path.join(BASE_DIR, "Excels", "Interviews.xlsx") + + +class InterviewsWindow(BaseWindow): + def __init__(self, role="admin"): + super().__init__() + self.role = role + loadUi(os.path.join(UI_DIR, "Interviews.ui"), self) + self.setWindowTitle("Interviews") + self.setFixedSize(1000, 600) + self.setWindowFlag(Qt.WindowType.FramelessWindowHint) + self.move_to_last_position() + + # Excel yükleme ve normalize edilmiş kolon isimleri + if os.path.exists(EXCEL_PATH): + try: + self.df = pd.read_excel(EXCEL_PATH) + except Exception as e: + QMessageBox.critical(self, "Dosya Hatası", f"Excel okunamadı:\n{e}") + self.df = pd.DataFrame() + else: + QMessageBox.critical(self, "Dosya Hatası", f"Excel dosyası bulunamadı:\n{EXCEL_PATH}") + self.df = pd.DataFrame() + + # Normalize: ayrıca indekslenmiş küçük harfli isimlere erişim için bir yardımcı dict oluştur + # (orijinal sütun adlarını koruyoruz ancak lowercase anahtarlarla arama yapacağız) + self.col_map = {} + if not self.df.empty: + for c in self.df.columns: + self.col_map[c.strip().lower()] = c # map: lowercase -> gerçek sütun adı + + # Olası sütun isimlerini tespit et (Türkçe ve İngilizce olasılıkları) + self.name_col = self._pick_column(["full name", "adınız soyadınız", "adınız soyadınız", "ad soyad", "adiniz soyadiniz"]) + self.submitted_col = self._pick_column(["submitted project", "proje gonderilis tarihi", "proje gönderiliş tarihi", "project submitted", "submitted"]) + self.received_col = self._pick_column(["received project", "projenin gelis tarihi", "proje gelis tarihi", "received"]) + + # Bağlantılar + self.pushButton_Return_REFERENCE_menu.clicked.connect(self.return_to_menu) + self.pushButton_EXIT.clicked.connect(self.close) + self.pushButton_SEARCH.clicked.connect(self.search_action) + self.pushButton_SUBMITTED_PROJECTS.clicked.connect(self.show_submitted_projects) + self.pushButton_RECEIVED_PROJECTS.clicked.connect(self.show_received_projects) + + # Tablo başlıkları (UI'da Türkçe görünmesini istersen burayı bırak) + self.tableWidget.setColumnCount(3) + self.tableWidget.setHorizontalHeaderLabels([ + "Adı Soyadı", "Proje Gönderiliş Tarihi", "Proje Geliş Tarihi" + ]) + + + def _pick_column(self, candidates): + """Verilen anahtar listesine göre ilk eşleşen gerçek sütun adını döndürür.""" + if self.df.empty: + return None + lower_cols = [c.lower().strip() for c in self.df.columns] + for cand in candidates: + cand_low = cand.lower().strip() + for i, lc in enumerate(lower_cols): + # Tam veya içinde eşleşme kabul edelim + if cand_low == lc or cand_low in lc or lc in cand_low: + return self.df.columns[i] + return None + + def fill_table(self, data: pd.DataFrame): + """Tabloyu verilen DataFrame'e göre doldurur (görsel Türkçe başlıklar).""" + self.tableWidget.setRowCount(0) + for row_idx, row in data.reset_index(drop=True).iterrows(): + self.tableWidget.insertRow(row_idx) + # Eğer sütun yoksa boş string koy + name_val = row.get(self.name_col, "") if self.name_col in row.index else row.get("Adınız Soyadınız", "") + sub_val = row.get(self.submitted_col, "") if self.submitted_col in row.index else row.get("Proje gonderilis tarihi", "") + rec_val = row.get(self.received_col, "") if self.received_col in row.index else row.get("Projenin gelis tarihi", "") + + self.tableWidget.setItem(row_idx, 0, QTableWidgetItem("" if pd.isna(name_val) else str(name_val))) + self.tableWidget.setItem(row_idx, 1, QTableWidgetItem("" if pd.isna(sub_val) else str(sub_val))) + self.tableWidget.setItem(row_idx, 2, QTableWidgetItem("" if pd.isna(rec_val) else str(rec_val))) + self.tableWidget.resizeColumnsToContents() + + def search_action(self): + """NAME sütununda BAŞLANGIÇ (startswith) araması yapar, case-insensitive.""" + if self.name_col is None: + QMessageBox.critical(self, "Hata", "Ad/Soyad sütunu bulunamadı (Excel).") + return + text = self.lineEdit.text().strip() + if text == "": + QMessageBox.information(self, "Bilgi", "Lütfen arama kutusuna bir metin girin.") + return + + # Case-insensitive, baştan eşleşme. NaN güvenli. + series = self.df[self.name_col].astype(str).str.strip() + mask = series.str.lower().str.startswith(text.lower(), na=False) + filtered = self.df[mask] + if filtered.empty: + QMessageBox.information(self, "Sonuç Yok", f"'{text}' ile başlayan isim bulunamadı.") + # istersen tümünü gösterme, şu an sadece uyarı + else: + self.fill_table(filtered) + + + def show_submitted_projects(self): + # """Projesini göndermiş adayları göster.""" + # Sütun adlarını normalize et (boşlukları ve büyük harfleri temizle) + self.df.columns = [col.strip().upper() for col in self.df.columns] + + if "SUBMITTED PROJECT" not in self.df.columns: + QMessageBox.critical(self, "Hata", "'SUBMITTED PROJECT' sütunu Excel dosyasında bulunamadı.") + return + + # Boş olmayan satırları filtrele + submitted = self.df[self.df["SUBMITTED PROJECT"].notna() & (self.df["SUBMITTED PROJECT"].astype(str).str.strip() != "")] + + if submitted.empty: + QMessageBox.information(self, "Bilgi", "Proje göndermiş aday bulunamadı.") + else: + self.fill_table(submitted) + + + + def show_received_projects(self): + # """Projesi GELMİŞ adayları göster.""" + if self.received_col is None: + QMessageBox.critical(self, "Hata", "Received (geliş) sütunu bulunamadı.") + return + + r = self.df[self.received_col] + mask = r.notna() & (r.astype(str).str.strip() != "") + res = self.df[mask] + if res.empty: + QMessageBox.information(self, "Bilgi", "Projesi gelmiş aday bulunamadı.") + else: + self.fill_table(res) + + + + + def return_to_menu(self): + from main import PreferenceAdminMenu, PreferenceMenu + if self.role.lower() == "admin": + self.pref_menu = PreferenceAdminMenu(role=self.role) + else: + self.pref_menu = PreferenceMenu(role=self.role) + self.pref_menu.show() + self.close() + + +# standalone test +if __name__ == "__main__": + import sys + app = QApplication(sys.argv) + w = InterviewsWindow(role="admin") + w.show() + sys.exit(app.exec()) +