EVM complete

This commit is contained in:
2026-03-23 03:31:44 -05:00
parent c88e344198
commit 8cd3aa5f84
32 changed files with 1605 additions and 31 deletions

View File

@@ -0,0 +1,125 @@
import json
from django.shortcuts import render, get_object_or_404, redirect
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from financial.models import Contract, ChargeNumber
from .models import Item
def is_developer(user):
return user.is_active and (user.is_superuser or user.groups.filter(name__iexact='developer').exists())
def developer_required(view_func):
def _wrapped_view(request, *args, **kwargs):
if is_developer(request.user):
return view_func(request, *args, **kwargs)
raise PermissionDenied
return _wrapped_view
@login_required
def board_view(request):
items = Item.objects.select_related('charge_number', 'charge_number__contract').all()
todo_items = items.filter(status=Item.Status.TODO)
in_progress_items = items.filter(status=Item.Status.IN_PROGRESS)
done_items = items.filter(status=Item.Status.DONE)
context = {
'todo_items': todo_items,
'in_progress_items': in_progress_items,
'done_items': done_items,
'statuses': Item.Status.choices,
'qbd_charge_numbers': ChargeNumber.objects.filter(charge_number_type='QBD'),
'is_developer': is_developer(request.user),
}
return render(request, 'planning/board.html', context)
@login_required
def backlog_view(request):
items = Item.objects.select_related('charge_number', 'charge_number__contract').all().order_by('-created_at')
status_filter = request.GET.get('status')
if status_filter and status_filter in dict(Item.Status.choices):
items = items.filter(status=status_filter)
context = {
'items': items,
'statuses': Item.Status.choices,
'qbd_charge_numbers': ChargeNumber.objects.filter(charge_number_type='QBD'),
'is_developer': is_developer(request.user),
}
return render(request, 'planning/backlog.html', context)
@login_required
@developer_required
@require_POST
def create_item(request):
title = request.POST.get('title')
description = request.POST.get('description', '')
charge_number_id = request.POST.get('charge_number')
next_url = request.POST.get('next', 'planning:board_view')
if title:
max_order = Item.objects.filter(status=Item.Status.TODO).count()
item = Item.objects.create(title=title, description=description, status=Item.Status.TODO, order=max_order)
if charge_number_id:
item.charge_number_id = charge_number_id
item.save()
return redirect(next_url)
@login_required
def item_detail(request, pk):
item = get_object_or_404(Item.objects.select_related('charge_number', 'charge_number__contract'), pk=pk)
context = {
'item': item,
'statuses': Item.Status.choices,
'qbd_charge_numbers': ChargeNumber.objects.filter(charge_number_type='QBD'),
'is_developer': is_developer(request.user),
}
return render(request, 'planning/partials/item_detail.html', context)
@login_required
@developer_required
@require_POST
def edit_item(request, pk):
item = get_object_or_404(Item, pk=pk)
item.title = request.POST.get('title', item.title)
item.description = request.POST.get('description', item.description)
item.status = request.POST.get('status', item.status)
charge_number_id = request.POST.get('charge_number')
if charge_number_id:
item.charge_number_id = charge_number_id
else:
item.charge_number = None
item.save()
next_url = request.POST.get('next', 'planning:board_view')
return redirect(next_url)
@login_required
@developer_required
@require_POST
def delete_item(request, pk):
item = get_object_or_404(Item, pk=pk)
item.delete()
next_url = request.POST.get('next', 'planning:board_view')
return redirect(next_url)
@login_required
@developer_required
@require_POST
def update_item_status(request, pk):
try:
data = json.loads(request.body)
new_status = data.get('status')
new_order = data.get('order')
item = get_object_or_404(Item, pk=pk)
if new_status and new_status in dict(Item.Status.choices):
item.status = new_status
if new_order is not None:
item.order = new_order
item.save()
return JsonResponse({'status': 'success'})
return JsonResponse({'status': 'error', 'message': 'Invalid status'}, status=400)
except Exception as e:
return JsonResponse({'status': 'error', 'message': str(e)}, status=400)