initial commit
This commit is contained in:
125
reports.py
Normal file
125
reports.py
Normal file
@@ -0,0 +1,125 @@
|
||||
import sqlite3
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
def connect_db():
|
||||
"""
|
||||
Connects to the SQLite database file and returns the connection object.
|
||||
If the file does not exist, it prints an an error message.
|
||||
"""
|
||||
db_file = 'time_tracker.db'
|
||||
if not os.path.exists(db_file):
|
||||
print(f"Error: Database file '{db_file}' not found. Please run the database creation script first.")
|
||||
return None
|
||||
return sqlite3.connect(db_file)
|
||||
|
||||
def unbilled_time_report():
|
||||
"""
|
||||
Generates a report of unbilled time entries for a selected client.
|
||||
"""
|
||||
conn = connect_db()
|
||||
if not conn:
|
||||
return
|
||||
|
||||
try:
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Display active clients for selection
|
||||
cursor.execute('SELECT client_id, client_name FROM clients WHERE active = 1 ORDER BY client_name')
|
||||
active_clients = cursor.fetchall()
|
||||
|
||||
if not active_clients:
|
||||
print("No active clients found to generate a report for.")
|
||||
return
|
||||
|
||||
print("\n--- Select a Client for Unbilled Time Report ---")
|
||||
for client_id, client_name in active_clients:
|
||||
print(f"{client_id}: {client_name}")
|
||||
print("0: Exit")
|
||||
print("--------------------------------------------------\n")
|
||||
|
||||
while True:
|
||||
try:
|
||||
choice = input("Enter the ID of the client (or 0 to exit): ")
|
||||
if choice == '0':
|
||||
print("Exiting report generation.")
|
||||
return
|
||||
|
||||
client_id = int(choice)
|
||||
if any(c[0] == client_id for c in active_clients):
|
||||
break
|
||||
else:
|
||||
print("Invalid client ID. Please enter a valid ID from the list.")
|
||||
except ValueError:
|
||||
print("Invalid input. Please enter a number.")
|
||||
|
||||
# Fetch client details and billing rate
|
||||
cursor.execute('SELECT client_name, billing_rate FROM clients WHERE client_id = ?', (client_id,))
|
||||
client_name, billing_rate = cursor.fetchone()
|
||||
|
||||
# Fetch unbilled time entries for the selected client, including description
|
||||
cursor.execute('''
|
||||
SELECT date, hours, description, project
|
||||
FROM time_tracking
|
||||
WHERE client_id = ? AND invoiced = 0
|
||||
ORDER BY date
|
||||
''', (client_id,))
|
||||
|
||||
time_entries = cursor.fetchall()
|
||||
|
||||
if not time_entries:
|
||||
print(f"\nNo unbilled time entries found for {client_name}.")
|
||||
return
|
||||
|
||||
# Calculate daily summary, descriptions, and total cost
|
||||
daily_summary = {}
|
||||
grand_total_cost = 0.0
|
||||
|
||||
for entry_date, hours, description, project in time_entries:
|
||||
if entry_date not in daily_summary:
|
||||
daily_summary[entry_date] = {'hours': 0.0, 'cost': 0.0, 'entries': []}
|
||||
|
||||
daily_summary[entry_date]['hours'] += hours
|
||||
daily_summary[entry_date]['cost'] += hours * billing_rate
|
||||
daily_summary[entry_date]['entries'].append({'description': description, 'project': project})
|
||||
grand_total_cost += hours * billing_rate
|
||||
|
||||
# Print the formatted report
|
||||
print(f"\n--- Unbilled Time Report for {client_name} ---")
|
||||
print(f"Total Unbilled Cost: ${grand_total_cost:.2f}\n")
|
||||
|
||||
for daily_date, summary in daily_summary.items():
|
||||
print(f"Date: {daily_date} | Hours: {summary['hours']:.2f} | Cost: ${summary['cost']:.2f}")
|
||||
for entry in summary['entries']:
|
||||
print(f" - Project: {entry['project']}, Description: {entry['description']}")
|
||||
print("-" * 32)
|
||||
|
||||
print(f"\nReport generated on {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
|
||||
except sqlite3.Error as e:
|
||||
print(f"An error occurred: {e}")
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
def main_menu():
|
||||
"""
|
||||
Displays the main menu and handles user choices.
|
||||
"""
|
||||
while True:
|
||||
print("\n--- Reports Menu ---")
|
||||
print("1: Unbilled Time")
|
||||
print("0: Exit")
|
||||
print("--------------------\n")
|
||||
choice = input("Enter your choice: ")
|
||||
|
||||
if choice == '1':
|
||||
unbilled_time_report()
|
||||
elif choice == '0':
|
||||
print("Exiting reports script. Goodbye!")
|
||||
break
|
||||
else:
|
||||
print("Invalid choice. Please try again.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main_menu()
|
||||
Reference in New Issue
Block a user