import os import json from datetime import datetime from enum import Enum import gspread from google.oauth2 import service_account class RequestStatus(Enum): NEW = "New" IN_PROGRESS = "In Progress" PENDING_INFO = "Pending Additional Info" DATA_COLLECTION = "Data Collection" READY_FOR_REVIEW = "Ready for Review" COMPLETED = "Completed" CANCELLED = "Cancelled" ON_HOLD = "On Hold" class SheetsLogger: def __init__(self): self.gc = None self.sheet = None self.initialize_client() def initialize_client(self): """Initialize Google Sheets client""" try: # Get credentials from environment variable creds_json = os.getenv('GOOGLE_SHEETS_CREDS') if not creds_json: raise ValueError("Google Sheets credentials not found in environment") # Parse credentials JSON creds_dict = json.loads(creds_json) # Create credentials object credentials = service_account.Credentials.from_service_account_info( creds_dict, scopes=['https://spreadsheets.google.com/feeds', 'https://www.googleapis.com/auth/spreadsheets', 'https://www.googleapis.com/auth/drive'] ) # Initialize gspread client self.gc = gspread.authorize(credentials) # Open spreadsheet by ID SHEET_ID = os.getenv('GOOGLE_SHEET_ID') if not SHEET_ID: raise ValueError("Google Sheet ID not found in environment") self.sheet = self.gc.open_by_key(SHEET_ID).sheet1 # Initialize headers if needed self.initialize_sheet() except Exception as e: print(f"Error initializing Google Sheets client: {str(e)}") self.gc = None self.sheet = None def initialize_sheet(self): """Initialize sheet with headers if needed""" headers = [ "Timestamp", "Name", "Employee ID", "Email", "Department", "Request Details", "Frequency", "Urgency", "User Summary", "Technical Analysis", "Status", "Notes", "Last Updated" ] try: # Check if headers exist existing_headers = self.sheet.row_values(1) if not existing_headers: self.sheet.insert_row(headers, 1) # Format header row self.sheet.format('A1:M1', { "backgroundColor": {"red": 0.2, "green": 0.2, "blue": 0.2}, "textFormat": {"bold": True, "foregroundColor": {"red": 1, "green": 1, "blue": 1}} }) # Set column widths self.sheet.format('A:M', { "wrapStrategy": "WRAP" }) except Exception as e: print(f"Error initializing headers: {str(e)}") def log_request(self, data): """Log a request to Google Sheets""" if not self.sheet: print("Sheet not initialized") return False try: # Prepare row data row = [ data.get('timestamp', datetime.now().strftime("%Y-%m-%d %H:%M:%S")), data.get('name', ''), data.get('employee_id', ''), data.get('email', ''), data.get('department', ''), data.get('request_details', ''), data.get('frequency', ''), data.get('urgency', ''), data.get('user_summary', ''), data.get('system_analysis', ''), RequestStatus.NEW.value, # Initial status '', # Empty notes datetime.now().strftime("%Y-%m-%d %H:%M:%S") # Last updated ] # Append row to sheet self.sheet.append_row(row) # Get the row number that was just added last_row = len(self.sheet.get_all_values()) # Apply conditional formatting for status self.apply_status_formatting(last_row) print(f"Successfully logged request to row {last_row}") return True except Exception as e: print(f"Error logging to sheet: {str(e)}") return False def apply_status_formatting(self, row_number): """Apply conditional formatting based on status""" status_cell = f'K{row_number}' formats = { RequestStatus.NEW.value: { "backgroundColor": {"red": 1, "green": 1, "blue": 0.8} # Light yellow }, RequestStatus.IN_PROGRESS.value: { "backgroundColor": {"red": 0.8, "green": 0.9, "blue": 1} # Light blue }, RequestStatus.PENDING_INFO.value: { "backgroundColor": {"red": 1, "green": 0.8, "blue": 0.8} # Light red }, RequestStatus.DATA_COLLECTION.value: { "backgroundColor": {"red": 0.8, "green": 1, "blue": 0.8} # Light green }, RequestStatus.READY_FOR_REVIEW.value: { "backgroundColor": {"red": 0.9, "green": 0.9, "blue": 1} # Light purple }, RequestStatus.COMPLETED.value: { "backgroundColor": {"red": 0.9, "green": 1, "blue": 0.9} # Lighter green }, RequestStatus.CANCELLED.value: { "backgroundColor": {"red": 0.9, "green": 0.9, "blue": 0.9} # Gray }, RequestStatus.ON_HOLD.value: { "backgroundColor": {"red": 1, "green": 0.9, "blue": 0.8} # Light orange } } try: status = self.sheet.acell(status_cell).value if status in formats: self.sheet.format(status_cell, formats[status]) except Exception as e: print(f"Error applying formatting: {str(e)}") def update_status(self, row_number, new_status, notes=None): """Update the status and notes of a request""" try: if not isinstance(new_status, str): if isinstance(new_status, RequestStatus): new_status = new_status.value else: raise ValueError("Invalid status type") # Update status self.sheet.update_cell(row_number, 11, new_status) # Column K # Update notes if provided if notes: current_notes = self.sheet.cell(row_number, 12).value # Column L timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") updated_notes = f"{current_notes}\n{timestamp}: {notes}" if current_notes else f"{timestamp}: {notes}" self.sheet.update_cell(row_number, 12, updated_notes) # Update last updated timestamp self.sheet.update_cell(row_number, 13, datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # Apply formatting self.apply_status_formatting(row_number) return True except Exception as e: print(f"Error updating status: {str(e)}") return False def get_request_history(self, request_id=None, employee_id=None): """Get request history filtered by ID or employee""" try: all_data = self.sheet.get_all_records() if request_id: return [row for row in all_data if str(row.get('Employee ID', '')).strip() == str(request_id).strip()] elif employee_id: return [row for row in all_data if str(row.get('Employee ID', '')).strip() == str(employee_id).strip()] return all_data except Exception as e: print(f"Error getting history: {str(e)}") return [] def get_request_by_row(self, row_number): """Get a specific request by row number""" try: if row_number < 2: # Row 1 is headers return None row_data = self.sheet.row_values(row_number) headers = self.sheet.row_values(1) return dict(zip(headers, row_data)) except Exception as e: print(f"Error getting row {row_number}: {str(e)}") return None