Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allocation Change Flow #330

Merged
merged 17 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
1d13786
#294: Created a 'is changable' allocation attribute property. When ch…
brisco17 Aug 6, 2021
0944bd6
#294: Created an 'is changeable' attribute for allocations which will…
brisco17 Aug 13, 2021
751f4c6
#294: Allocation change flow complete
brisco17 Oct 29, 2021
289b646
Merge branch 'ubccr:master' into #294-change-allocation-attributes
brisco17 Oct 31, 2021
ff75543
#294: Recreated allocation change request migration file so that the …
brisco17 Nov 2, 2021
1ab71b9
Merge branch '#294-change-allocation-attributes' of github.com:brisco…
brisco17 Nov 2, 2021
0f57306
#294: Addressed PR comments. The 'request change' button on the 'Allo…
brisco17 Nov 5, 2021
44abfbf
#294: Created new ColdFront config vars that allow users to decide wh…
brisco17 Nov 11, 2021
fc4cc37
#294: Fixed allocation change form submission issue ('ManagementForm …
brisco17 Nov 16, 2021
43f9c4b
#294: Created a data migration file so that existing ColdFront instan…
brisco17 Nov 17, 2021
64eebde
#294: Updated the Allocation Update Form in the Allocation Detail pag…
brisco17 Nov 17, 2021
254f150
Made several requested updates/bug fixes such as updating the allocat…
brisco17 Nov 23, 2021
d2881d7
#294: Patching up a line in the allocation views.py file that was acc…
brisco17 Nov 23, 2021
08a4470
#294: Updated admin form in Allocation Change Detail template to post…
brisco17 Dec 1, 2021
3754bac
#294: Allocation detail page now has a mechanism for admins to edit a…
brisco17 Dec 20, 2021
a94ccc1
#294: Allocation change request update form complete
brisco17 Dec 22, 2021
526f9d9
#294: Updated Allocation Change Detail page so that only admins see t…
brisco17 Dec 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions coldfront/config/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#------------------------------------------------------------------------------
# Allocation related
#------------------------------------------------------------------------------
ALLOCATION_ENABLE_CHANGE_REQUESTS_BY_DEFAULT = ENV.bool('ALLOCATION_ENABLE_CHANGE_REQUESTS', default=True)
ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS = ENV.list('ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS', cast=int, default=[30, 60, 90])
ALLOCATION_ENABLE_ALLOCATION_RENEWAL = ENV.bool('ALLOCATION_ENABLE_ALLOCATION_RENEWAL', default=True)
ALLOCATION_FUNCS_ON_EXPIRE = ['coldfront.core.allocation.utils.test_allocation_function', ]

Expand Down
21 changes: 20 additions & 1 deletion coldfront/core/allocation/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
AllocationAttribute,
AllocationAttributeType,
AllocationAttributeUsage,
AllocationChangeRequest,
AllocationAttributeChangeRequest,
AllocationStatusChoice,
AllocationChangeStatusChoice,
AllocationUser,
AllocationUserNote,
AllocationUserStatusChoice,
Expand Down Expand Up @@ -53,7 +56,7 @@ class AllocationAdmin(SimpleHistoryAdmin):
readonly_fields_change = (
'project', 'justification', 'created', 'modified',)
fields_change = ('project', 'resources', 'quantity', 'justification',
'status', 'start_date', 'end_date', 'description', 'created', 'modified', 'is_locked')
'status', 'start_date', 'end_date', 'description', 'created', 'modified', 'is_locked', 'is_changeable')
list_display = ('pk', 'project_title', 'project_pi', 'resource', 'quantity',
'justification', 'start_date', 'end_date', 'status', 'created', 'modified', )
inlines = [AllocationUserInline,
Expand Down Expand Up @@ -343,3 +346,19 @@ def project_pi(self, obj):
@admin.register(AllocationAccount)
class AllocationAccountAdmin(SimpleHistoryAdmin):
list_display = ('name', 'user', )


@admin.register(AllocationChangeStatusChoice)
class AllocationChangeStatusChoiceAdmin(admin.ModelAdmin):
list_display = ('name', )


@admin.register(AllocationChangeRequest)
class AllocationChangeRequestAdmin(admin.ModelAdmin):
list_display = ('pk', 'allocation', 'status', 'end_date_extension', 'justification', 'notes', )


@admin.register(AllocationAttributeChangeRequest)
class AllocationChangeStatusChoiceAdmin(admin.ModelAdmin):
list_display = ('pk', 'allocation_change_request', 'allocation_attribute', 'new_value', )

76 changes: 76 additions & 0 deletions coldfront/core/allocation/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from coldfront.core.allocation.models import (Allocation, AllocationAccount,
AllocationAttributeType,
AllocationAttribute,
AllocationStatusChoice)
from coldfront.core.allocation.utils import get_user_resources
from coldfront.core.project.models import Project
Expand All @@ -11,6 +12,8 @@

ALLOCATION_ACCOUNT_ENABLED = import_from_settings(
'ALLOCATION_ACCOUNT_ENABLED', False)
ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS = import_from_settings(
'ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS', [])


class AllocationForm(forms.Form):
Expand Down Expand Up @@ -64,6 +67,7 @@ class AllocationUpdateForm(forms.Form):
description = forms.CharField(max_length=512,
label='Description',
required=False)
is_changeable = forms.BooleanField(required=False)

def clean(self):
cleaned_data = super().clean()
Expand Down Expand Up @@ -174,3 +178,75 @@ class AllocationAccountForm(forms.ModelForm):
class Meta:
model = AllocationAccount
fields = ['name', ]


class AllocationAttributeChangeForm(forms.Form):
pk = forms.IntegerField(required=False, disabled=True)
name = forms.CharField(max_length=150, required=False, disabled=True)
value = forms.CharField(max_length=150, required=False, disabled=True)
new_value = forms.CharField(max_length=150, required=False, disabled=False)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['pk'].widget = forms.HiddenInput()

def clean(self):
cleaned_data = super().clean()

if cleaned_data.get('new_value') != "":
allocation_attribute = AllocationAttribute.objects.get(pk=cleaned_data.get('pk'))
allocation_attribute.value = cleaned_data.get('new_value')
allocation_attribute.clean()


class AllocationAttributeUpdateForm(forms.Form):
change_pk = forms.IntegerField(required=False, disabled=True)
attribute_pk = forms.IntegerField(required=False, disabled=True)
name = forms.CharField(max_length=150, required=False, disabled=True)
value = forms.CharField(max_length=150, required=False, disabled=True)
new_value = forms.CharField(max_length=150, required=False, disabled=False)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['change_pk'].widget = forms.HiddenInput()
self.fields['attribute_pk'].widget = forms.HiddenInput()

def clean(self):
cleaned_data = super().clean()
allocation_attribute = AllocationAttribute.objects.get(pk=cleaned_data.get('attribute_pk'))

allocation_attribute.value = cleaned_data.get('new_value')
allocation_attribute.clean()


class AllocationChangeForm(forms.Form):
EXTENSION_CHOICES = [
(0, "No Extension")
]
for choice in ALLOCATION_CHANGE_REQUEST_EXTENSION_DAYS:
EXTENSION_CHOICES.append((choice, "{} days".format(choice)))

end_date_extension = forms.TypedChoiceField(
label='Request End Date Extension',
choices = EXTENSION_CHOICES,
coerce=int,
required=False,
empty_value=0,)
justification = forms.CharField(
label='Justification for Changes',
widget=forms.Textarea,
required=False,
help_text='Justification for requesting this allocation change request.')

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)


class AllocationChangeNoteForm(forms.Form):
notes = forms.CharField(
max_length=512,
label='Notes',
required=False,
widget=forms.Textarea,
help_text="Leave any feedback about the allocation change request.")

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from coldfront.core.allocation.models import (AttributeType,
AllocationAttributeType,
AllocationStatusChoice,
AllocationChangeStatusChoice,
AllocationUserStatusChoice)


Expand All @@ -20,6 +21,9 @@ def handle(self, *args, **options):
'Renewal Requested', 'Revoked', 'Unpaid',):
AllocationStatusChoice.objects.get_or_create(name=choice)

for choice in ('Pending', 'Approved', 'Denied',):
AllocationChangeStatusChoice.objects.get_or_create(name=choice)

for choice in ('Active', 'Error', 'Removed', ):
AllocationUserStatusChoice.objects.get_or_create(name=choice)

Expand Down
135 changes: 135 additions & 0 deletions coldfront/core/allocation/migrations/0004_auto_20211102_1017.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Generated by Django 2.2.18 on 2021-11-02 14:17

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import model_utils.fields
import simple_history.models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('allocation', '0003_auto_20191018_1049'),
]

operations = [
migrations.CreateModel(
name='AllocationChangeRequest',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('end_date_extension', models.IntegerField(blank=True, null=True)),
('justification', models.TextField()),
('notes', models.CharField(blank=True, max_length=512, null=True)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='AllocationChangeStatusChoice',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('name', models.CharField(max_length=64)),
],
options={
'ordering': ['name'],
},
),
migrations.AddField(
model_name='allocation',
name='is_changeable',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='allocationattributetype',
name='is_changeable',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='historicalallocation',
name='is_changeable',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='historicalallocationattributetype',
name='is_changeable',
field=models.BooleanField(default=False),
),
migrations.CreateModel(
name='HistoricalAllocationChangeRequest',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('end_date_extension', models.IntegerField(blank=True, null=True)),
('justification', models.TextField()),
('notes', models.CharField(blank=True, max_length=512, null=True)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('allocation', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='allocation.Allocation')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('status', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='allocation.AllocationChangeStatusChoice', verbose_name='Status')),
],
options={
'verbose_name': 'historical allocation change request',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.CreateModel(
name='HistoricalAllocationAttributeChangeRequest',
fields=[
('id', models.IntegerField(auto_created=True, blank=True, db_index=True, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('new_value', models.CharField(max_length=128)),
('history_id', models.AutoField(primary_key=True, serialize=False)),
('history_date', models.DateTimeField()),
('history_change_reason', models.CharField(max_length=100, null=True)),
('history_type', models.CharField(choices=[('+', 'Created'), ('~', 'Changed'), ('-', 'Deleted')], max_length=1)),
('allocation_attribute', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='allocation.AllocationAttribute')),
('allocation_change_request', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='allocation.AllocationChangeRequest')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'historical allocation attribute change request',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': 'history_date',
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
migrations.AddField(
model_name='allocationchangerequest',
name='allocation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='allocation.Allocation'),
),
migrations.AddField(
model_name='allocationchangerequest',
name='status',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='allocation.AllocationChangeStatusChoice', verbose_name='Status'),
),
migrations.CreateModel(
name='AllocationAttributeChangeRequest',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
('new_value', models.CharField(max_length=128)),
('allocation_attribute', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='allocation.AllocationAttribute')),
('allocation_change_request', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='allocation.AllocationChangeRequest')),
],
options={
'abstract': False,
},
),
]
20 changes: 20 additions & 0 deletions coldfront/core/allocation/migrations/0005_auto_20211117_1413.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Generated by Django 2.2.24 on 2021-11-17 19:13

from django.db import migrations


def create_status_choices(apps, schema_editor):
AllocationChangeStatusChoice = apps.get_model('allocation', "AllocationChangeStatusChoice")
for choice in ('Pending', 'Approved', 'Denied',):
AllocationChangeStatusChoice.objects.get_or_create(name=choice)


class Migration(migrations.Migration):

dependencies = [
('allocation', '0004_auto_20211102_1017'),
]

operations = [
migrations.RunPython(create_status_choices),
]
Loading