Skip to content

Commit

Permalink
feat: adds a LicenseTransferJob model and admin
Browse files Browse the repository at this point in the history
Also installs django-autocomplete-light for help to support
advanced admin autocomplete field filtering, and therefore
runs make upgrade to pull in some other new package versions.
  • Loading branch information
iloveagent57 committed Oct 23, 2023
1 parent 9335ec3 commit 763a33b
Show file tree
Hide file tree
Showing 19 changed files with 665 additions and 83 deletions.
54 changes: 54 additions & 0 deletions license_manager/apps/subscriptions/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@
from license_manager.apps.subscriptions.exceptions import CustomerAgreementError
from license_manager.apps.subscriptions.forms import (
CustomerAgreementAdminForm,
LicenseTransferJobAdminForm,
ProductForm,
SubscriptionPlanForm,
SubscriptionPlanRenewalForm,
)
from license_manager.apps.subscriptions.models import (
CustomerAgreement,
License,
LicenseTransferJob,
Notification,
PlanType,
Product,
Expand Down Expand Up @@ -657,3 +659,55 @@ class NotificationAdmin(admin.ModelAdmin):

def has_change_permission(self, request, obj=None):
return False


@admin.register(LicenseTransferJob)
class LicenseTransferJobAdmin(admin.ModelAdmin):
form = LicenseTransferJobAdminForm

list_display = (
'id',
'customer_agreement',
'old_subscription_plan',
'new_subscription_plan',
'completed_at',
'is_dry_run',
)

list_filter = (
'is_dry_run',
)

search_fields = (
'customer_agreement__enterprise_customer_uuid__startswith',
'customer_agreement__enterprise_customer_slug__startswith',
'customer_agreement__enterprise_customer_name__startswith',
'old_subscription_plan',
'new_subscription_plan',
)

sortable_by = (
'id',
'completed_at',
'is_dry_run',
'customer_agreement',
)

readonly_fields = (
'completed_at',
'processed_results',
)

actions = ['process_transfer_jobs']

def get_queryset(self, request):
return super().get_queryset(request).select_related(
'customer_agreement',
'old_subscription_plan',
'new_subscription_plan',
)

@admin.action(description="Process selected license transfer jobs")
def process_transfer_jobs(self, request, queryset):
for transfer_job in queryset:
transfer_job.process()
39 changes: 38 additions & 1 deletion license_manager/apps/subscriptions/forms.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""
Forms to be used in the subscriptions django app.
"""

import json
import logging

from dal import autocomplete
from django import forms
from django.conf import settings
from django.utils.translation import gettext as _
Expand All @@ -22,6 +23,7 @@
)
from license_manager.apps.subscriptions.models import (
CustomerAgreement,
LicenseTransferJob,
Product,
SubscriptionPlan,
SubscriptionPlanRenewal,
Expand Down Expand Up @@ -401,3 +403,38 @@ def is_valid(self):
return False

return True


class LicenseTransferJobAdminForm(forms.ModelForm):
class Meta:
model = LicenseTransferJob
fields = '__all__'
# Use django-autocomplete-light to filter the available
# subscription_plan choices to only those related to
# the selected customer agreement. Works for both
# records that don't yet exist (on transfer job creation)
# and for modification of existing transfer job records.
# See urls_admin.py for the view that does this filtering,
# and see static/filtered_subscription_admin.js for
# the jQuery code that clears subscription plan selections
# when the selected customer agreement is changed.
widgets = {
'old_subscription_plan': autocomplete.ModelSelect2(
url='filtered_subscription_plan_admin',
# forward the customer_agreement field's value
# into our custom autocomplete field in urls_admin.py
forward=['customer_agreement'],
),
'new_subscription_plan': autocomplete.ModelSelect2(
url='filtered_subscription_plan_admin',
# forward the customer_agreement field's value
# into our custom autocomplete field in urls_admin.py
forward=['customer_agreement'],
),
}

class Media:
js = (
'filtered_subscription_admin.js',
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Generated by Django 4.2.6 on 2023-10-23 20:03

from django.conf import settings
import django.core.serializers.json
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),
('subscriptions', '0061_auto_20230927_1119'),
]

operations = [
migrations.CreateModel(
name='LicenseTransferJob',
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')),
('completed_at', models.DateTimeField(blank=True, help_text='The time at which the job was successfully processed.', null=True)),
('notes', models.TextField(blank=True, help_text='Say something about why the licenses are being transferred.', null=True)),
('is_dry_run', models.BooleanField(default=False)),
('delimiter', models.CharField(choices=[('newline', 'Newline character'), ('comma', 'Comma character'), ('pipe', 'Pipe character')], default='newline', max_length=8)),
('license_uuids_raw', models.TextField(help_text='Delimitted list of license_uuids to transfer')),
('processed_results', models.JSONField(blank=True, encoder=django.core.serializers.json.DjangoJSONEncoder, help_text='Raw results of what licenses were changed, either in dry-run form, or actual form.', null=True)),
('customer_agreement', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='license_transfer_jobs', to='subscriptions.customeragreement')),
('new_subscription_plan', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='license_transfer_jobs_new', to='subscriptions.subscriptionplan')),
('old_subscription_plan', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='license_transfer_jobs_old', to='subscriptions.subscriptionplan')),
],
options={
'verbose_name': 'License Transfer Job',
'verbose_name_plural': 'License Transfer Jobs',
},
),
migrations.CreateModel(
name='HistoricalLicenseTransferJob',
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')),
('completed_at', models.DateTimeField(blank=True, help_text='The time at which the job was successfully processed.', null=True)),
('notes', models.TextField(blank=True, help_text='Say something about why the licenses are being transferred.', null=True)),
('is_dry_run', models.BooleanField(default=False)),
('delimiter', models.CharField(choices=[('newline', 'Newline character'), ('comma', 'Comma character'), ('pipe', 'Pipe character')], default='newline', max_length=8)),
('license_uuids_raw', models.TextField(help_text='Delimitted list of license_uuids to transfer')),
('processed_results', models.JSONField(blank=True, encoder=django.core.serializers.json.DjangoJSONEncoder, help_text='Raw results of what licenses were changed, either in dry-run form, or actual form.', 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)),
('customer_agreement', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='subscriptions.customeragreement')),
('history_user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)),
('new_subscription_plan', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='subscriptions.subscriptionplan')),
('old_subscription_plan', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='+', to='subscriptions.subscriptionplan')),
],
options={
'verbose_name': 'historical License Transfer Job',
'verbose_name_plural': 'historical License Transfer Jobs',
'ordering': ('-history_date', '-history_id'),
'get_latest_by': ('history_date', 'history_id'),
},
bases=(simple_history.models.HistoricalChanges, models.Model),
),
]
Loading

0 comments on commit 763a33b

Please sign in to comment.