210 lines
7.8 KiB
Python
210 lines
7.8 KiB
Python
from django.shortcuts import render, redirect
|
|
from django.contrib.auth.decorators import user_passes_test
|
|
from .forms import EmployeeForm, ContractForm, ChargeNumberForm, TimeLogForm, NewEmployeeForm
|
|
from .models import Contract, TimeCard, TimeCardCell, Employee
|
|
from django.utils import timezone
|
|
from django.db.models import Sum
|
|
from datetime import timedelta
|
|
import json
|
|
|
|
def is_admin(user):
|
|
return user.is_active and user.is_superuser
|
|
|
|
@user_passes_test(is_admin)
|
|
def index(request):
|
|
contracts = Contract.objects.all()
|
|
for c in contracts:
|
|
total = TimeCardCell.objects.filter(contract=c).aggregate(Sum('hour'))['hour__sum']
|
|
c.total_logged = total if total else 0.0
|
|
|
|
employees = Employee.objects.all()
|
|
employee_data = []
|
|
for e in employees:
|
|
contract_hours = []
|
|
for c in contracts:
|
|
total_e_c = TimeCardCell.objects.filter(contract=c, timeCard__employee=e).aggregate(Sum('hour'))['hour__sum']
|
|
contract_hours.append({'contract': c, 'hours': total_e_c if total_e_c else 0.0})
|
|
employee_data.append({'employee': e, 'contract_hours': contract_hours})
|
|
|
|
return render(request, "financial/index.html", {
|
|
'contracts': contracts,
|
|
'employee_data': employee_data
|
|
})
|
|
|
|
@user_passes_test(is_admin)
|
|
def new_employee(request):
|
|
if request.method == "POST":
|
|
form = NewEmployeeForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
return redirect('financial_index')
|
|
else:
|
|
form = NewEmployeeForm()
|
|
return render(request, 'financial/new_employee.html', {"form": form})
|
|
|
|
@user_passes_test(is_admin)
|
|
def contracts(request):
|
|
contracts_list = Contract.objects.all()
|
|
today = timezone.now().date()
|
|
|
|
chart_data_list = []
|
|
|
|
for c in contracts_list:
|
|
cells = TimeCardCell.objects.filter(contract=c).select_related('timeCard__employee').order_by('date')
|
|
|
|
total_hours = sum((cell.hour or 0.0) for cell in cells)
|
|
total_money = sum((cell.hour or 0.0) * cell.timeCard.employee.hourly_salary for cell in cells)
|
|
|
|
c.total_hours_spent = total_hours
|
|
c.total_money_spent = total_money
|
|
c.remaining_hours = max(0, c.budget_hours - total_hours)
|
|
|
|
budget_amt = c.funded_amount if c.funded_amount > 0 else c.proposed_amount
|
|
c.remaining_money = max(0, budget_amt - total_money)
|
|
|
|
proj_end = None
|
|
|
|
if cells.exists():
|
|
first_date = cells.first().date or c.baseline_start or today
|
|
last_date = cells.last().date or today
|
|
days_elapsed = (last_date - first_date).days
|
|
if days_elapsed <= 0:
|
|
days_elapsed = 1
|
|
|
|
daily_hour_burn = total_hours / days_elapsed
|
|
daily_money_burn = total_money / days_elapsed
|
|
|
|
days_out_hours = (c.remaining_hours / daily_hour_burn) if daily_hour_burn > 0 else 9999
|
|
days_out_money = (c.remaining_money / daily_money_burn) if daily_money_burn > 0 else 9999
|
|
|
|
days_out = max(days_out_hours, days_out_money)
|
|
|
|
if days_out < 9999:
|
|
proj_end = last_date + timedelta(days=int(days_out))
|
|
|
|
c.projected_end_date = proj_end if proj_end else "N/A"
|
|
|
|
start_dt = str(c.baseline_start or today)
|
|
end_dt = str(proj_end or (today + timedelta(days=30)))
|
|
|
|
chart_data_list.append({
|
|
'name': c.name,
|
|
'start_date': start_dt,
|
|
'today': str(today),
|
|
'projected_end': end_dt,
|
|
'budget': float(budget_amt),
|
|
'spent': float(total_money),
|
|
'remaining': float(c.remaining_money)
|
|
})
|
|
|
|
return render(request, 'financial/contracts.html', {
|
|
'contracts': contracts_list,
|
|
'chart_data_json': json.dumps(chart_data_list)
|
|
})
|
|
|
|
@user_passes_test(is_admin)
|
|
def contract_detail(request, contract_slug):
|
|
contract = Contract.objects.filter(slug=contract_slug).first()
|
|
if request.method == 'POST':
|
|
form = ContractForm(request.POST, instance=contract)
|
|
if form.is_valid():
|
|
form.save()
|
|
return redirect('contracts')
|
|
else:
|
|
form = ContractForm(instance=contract)
|
|
charge_number_form = ChargeNumberForm()
|
|
return render(request, 'financial/contract_detail.html', {'is_new': False, 'form': form, 'charge_number_form':charge_number_form, 'contract': contract})
|
|
|
|
@user_passes_test(is_admin)
|
|
def new_contract(request):
|
|
if request.method == "POST":
|
|
form = ContractForm(request.POST)
|
|
if form.is_valid():
|
|
form.save()
|
|
return redirect('contracts')
|
|
else:
|
|
form = ContractForm()
|
|
return render(request, 'financial/contract_detail.html', {"form": form, 'is_new': True})
|
|
|
|
@user_passes_test(is_admin)
|
|
def timekeeping(request):
|
|
if request.method == "POST":
|
|
form = TimeLogForm(request.POST)
|
|
if form.is_valid():
|
|
employee = Employee.objects.filter(user=request.user).first()
|
|
if not employee:
|
|
employee = Employee.objects.first()
|
|
if not employee:
|
|
return render(request, 'financial/timekeeping.html', {"form": form, "error": "No Employee exists. Cannot auto-create TimeCard. Please create an Employee first."})
|
|
|
|
time_card, _ = TimeCard.objects.get_or_create(employee=employee, startDate=timezone.now().date(), endDate=timezone.now().date())
|
|
cell = form.save(commit=False)
|
|
cell.timeCard = time_card
|
|
cell.save()
|
|
return redirect('financial_index')
|
|
else:
|
|
form = TimeLogForm()
|
|
return render(request, 'financial/timekeeping.html', {'form': form})
|
|
|
|
@user_passes_test(is_admin)
|
|
def time_logs(request):
|
|
logs = TimeCardCell.objects.all().order_by('-date', '-created')
|
|
return render(request, 'financial/time_logs.html', {'logs': logs})
|
|
|
|
@user_passes_test(is_admin)
|
|
def edit_time_log(request, log_id):
|
|
log_entry = TimeCardCell.objects.filter(id=log_id).first()
|
|
if not log_entry:
|
|
return redirect('time_logs')
|
|
|
|
if request.method == "POST":
|
|
form = TimeLogForm(request.POST, instance=log_entry)
|
|
if form.is_valid():
|
|
form.save()
|
|
return redirect('time_logs')
|
|
else:
|
|
form = TimeLogForm(instance=log_entry)
|
|
|
|
return render(request, 'financial/edit_time_log.html', {'form': form, 'log': log_entry})
|
|
|
|
@user_passes_test(is_admin)
|
|
def delete_time_log(request, log_id):
|
|
if request.method == "POST":
|
|
log_entry = TimeCardCell.objects.filter(id=log_id).first()
|
|
if log_entry:
|
|
log_entry.delete()
|
|
return redirect('time_logs')
|
|
|
|
@user_passes_test(is_admin)
|
|
def client_reports(request):
|
|
contracts = Contract.objects.all()
|
|
for c in contracts:
|
|
total = TimeCardCell.objects.filter(contract=c).aggregate(Sum('hour'))['hour__sum']
|
|
c.total_logged = total if total else 0.0
|
|
c.remaining_budget = c.budget_hours - c.total_logged
|
|
return render(request, 'financial/reports.html', {'contracts': contracts})
|
|
|
|
@user_passes_test(is_admin)
|
|
def update_charge_number(request, charge_number_slug):
|
|
return render(request, 'financial/not_created.html', {})
|
|
|
|
@user_passes_test(is_admin)
|
|
def new_charge_number(request, charge_number_slug):
|
|
return render(request, 'financial/not_created.html', {})
|
|
|
|
@user_passes_test(is_admin)
|
|
def timeapproval(request):
|
|
return render(request, 'financial/not_created.html', {})
|
|
|
|
@user_passes_test(is_admin)
|
|
def chargenumber(request):
|
|
return render(request, 'financial/not_created.html', {})
|
|
|
|
@user_passes_test(is_admin)
|
|
def procurement(request):
|
|
return render(request, 'financial/procurement.html', {})
|
|
|
|
@user_passes_test(is_admin)
|
|
def profile(request):
|
|
form = EmployeeForm()
|
|
return render(request, 'financial/profile.html', {'form': form}) |