add /shipping_vouchers endpoint
This commit is contained in:
parent
2f354130da
commit
f11758607e
6 changed files with 123 additions and 5 deletions
|
@ -1,6 +1,6 @@
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
from tickets.models import IssueThread, Comment, StateChange
|
from tickets.models import IssueThread, Comment, StateChange, Assignment, ShippingVoucher
|
||||||
|
|
||||||
|
|
||||||
class IssueThreadAdmin(admin.ModelAdmin):
|
class IssueThreadAdmin(admin.ModelAdmin):
|
||||||
|
@ -15,6 +15,16 @@ class StateChangeAdmin(admin.ModelAdmin):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class AssignmentAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ShippingVouchersAdmin(admin.ModelAdmin):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(IssueThread, IssueThreadAdmin)
|
admin.site.register(IssueThread, IssueThreadAdmin)
|
||||||
admin.site.register(Comment, CommentAdmin)
|
admin.site.register(Comment, CommentAdmin)
|
||||||
admin.site.register(StateChange, StateChangeAdmin)
|
admin.site.register(StateChange, StateChangeAdmin)
|
||||||
|
admin.site.register(Assignment, AssignmentAdmin)
|
||||||
|
admin.site.register(ShippingVoucher, ShippingVouchersAdmin)
|
||||||
|
|
|
@ -13,8 +13,8 @@ from core.settings import MAIL_DOMAIN
|
||||||
from mail.models import Email
|
from mail.models import Email
|
||||||
from mail.protocol import send_smtp, make_reply, collect_references
|
from mail.protocol import send_smtp, make_reply, collect_references
|
||||||
from notify_sessions.models import SystemEvent
|
from notify_sessions.models import SystemEvent
|
||||||
from tickets.models import IssueThread, Comment, STATE_CHOICES
|
from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher
|
||||||
from tickets.serializers import IssueSerializer, CommentSerializer
|
from tickets.serializers import IssueSerializer, CommentSerializer, ShippingVoucherSerializer
|
||||||
|
|
||||||
|
|
||||||
class IssueViewSet(viewsets.ModelViewSet):
|
class IssueViewSet(viewsets.ModelViewSet):
|
||||||
|
@ -22,6 +22,11 @@ class IssueViewSet(viewsets.ModelViewSet):
|
||||||
queryset = IssueThread.objects.all()
|
queryset = IssueThread.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
class ShippingVoucherViewSet(viewsets.ModelViewSet):
|
||||||
|
serializer_class = ShippingVoucherSerializer
|
||||||
|
queryset = ShippingVoucher.objects.all()
|
||||||
|
|
||||||
|
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
@permission_required('tickets.add_issuethread', raise_exception=True)
|
@permission_required('tickets.add_issuethread', raise_exception=True)
|
||||||
|
@ -113,6 +118,7 @@ def add_comment(request, pk):
|
||||||
|
|
||||||
router = routers.SimpleRouter()
|
router = routers.SimpleRouter()
|
||||||
router.register(r'tickets', IssueViewSet, basename='issues')
|
router.register(r'tickets', IssueViewSet, basename='issues')
|
||||||
|
router.register(r'shipping_vouchers', ShippingVoucherViewSet, basename='shipping_vouchers')
|
||||||
|
|
||||||
urlpatterns = ([
|
urlpatterns = ([
|
||||||
re_path(r'^tickets/(?P<pk>\d+)/reply/$', reply, name='reply'),
|
re_path(r'^tickets/(?P<pk>\d+)/reply/$', reply, name='reply'),
|
||||||
|
|
25
core/tickets/migrations/0009_shippingvoucher.py
Normal file
25
core/tickets/migrations/0009_shippingvoucher.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 4.2.7 on 2024-06-23 00:47
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tickets', '0008_alter_issuethread_options_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='ShippingVoucher',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(primary_key=True, serialize=False)),
|
||||||
|
('voucher', models.CharField(max_length=255)),
|
||||||
|
('type', models.CharField(max_length=255)),
|
||||||
|
('timestamp', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('used_at', models.DateTimeField(null=True)),
|
||||||
|
('issue_thread', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='shipping_vouchers', to='tickets.issuethread')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,4 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
from django_softdelete.models import SoftDeleteModel
|
from django_softdelete.models import SoftDeleteModel
|
||||||
|
|
||||||
from authentication.models import ExtendedUser
|
from authentication.models import ExtendedUser
|
||||||
|
@ -116,3 +117,20 @@ class Assignment(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return str(self.issue_thread) + ' assigned to ' + self.assigned_to.username
|
return str(self.issue_thread) + ' assigned to ' + self.assigned_to.username
|
||||||
|
|
||||||
|
|
||||||
|
class ShippingVoucher(models.Model):
|
||||||
|
id = models.AutoField(primary_key=True)
|
||||||
|
issue_thread = models.ForeignKey(IssueThread, on_delete=models.CASCADE, related_name='shipping_vouchers', null=True)
|
||||||
|
voucher = models.CharField(max_length=255)
|
||||||
|
type = models.CharField(max_length=255)
|
||||||
|
timestamp = models.DateTimeField(auto_now_add=True)
|
||||||
|
used_at = models.DateTimeField(null=True)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.voucher + ' (' + self.type + ')'
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if self.used_at is None and self.issue_thread is not None:
|
||||||
|
self.used_at = timezone.now()
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
|
@ -2,7 +2,7 @@ from rest_framework import serializers
|
||||||
|
|
||||||
from authentication.models import ExtendedUser
|
from authentication.models import ExtendedUser
|
||||||
from mail.api_v2 import AttachmentSerializer
|
from mail.api_v2 import AttachmentSerializer
|
||||||
from tickets.models import IssueThread, Comment, STATE_CHOICES
|
from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher
|
||||||
|
|
||||||
|
|
||||||
class CommentSerializer(serializers.ModelSerializer):
|
class CommentSerializer(serializers.ModelSerializer):
|
||||||
|
@ -28,6 +28,13 @@ class StateSerializer(serializers.Serializer):
|
||||||
return obj['value']
|
return obj['value']
|
||||||
|
|
||||||
|
|
||||||
|
class ShippingVoucherSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = ShippingVoucher
|
||||||
|
fields = ('id', 'voucher', 'type', 'timestamp', 'issue_thread', 'used_at')
|
||||||
|
read_only_fields = ('id', 'timestamp', 'used_at')
|
||||||
|
|
||||||
|
|
||||||
class IssueSerializer(serializers.ModelSerializer):
|
class IssueSerializer(serializers.ModelSerializer):
|
||||||
timeline = serializers.SerializerMethodField()
|
timeline = serializers.SerializerMethodField()
|
||||||
last_activity = serializers.SerializerMethodField()
|
last_activity = serializers.SerializerMethodField()
|
||||||
|
@ -60,7 +67,10 @@ class IssueSerializer(serializers.ModelSerializer):
|
||||||
if self.state_changes.count() > 0 else None
|
if self.state_changes.count() > 0 else None
|
||||||
last_comment = self.comments.order_by('-timestamp').first().timestamp if self.comments.count() > 0 else None
|
last_comment = self.comments.order_by('-timestamp').first().timestamp if self.comments.count() > 0 else None
|
||||||
last_mail = self.emails.order_by('-timestamp').first().timestamp if self.emails.count() > 0 else None
|
last_mail = self.emails.order_by('-timestamp').first().timestamp if self.emails.count() > 0 else None
|
||||||
args = [x for x in [last_state_change, last_comment, last_mail] if x is not None]
|
last_assignment = self.assignments.order_by('-timestamp').first().timestamp if \
|
||||||
|
self.assignments.count() > 0 else None
|
||||||
|
args = [x for x in [last_state_change, last_comment, last_mail, last_assignment] if
|
||||||
|
x is not None]
|
||||||
return max(args)
|
return max(args)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
|
@ -100,6 +110,14 @@ class IssueSerializer(serializers.ModelSerializer):
|
||||||
'timestamp': assignment.timestamp,
|
'timestamp': assignment.timestamp,
|
||||||
'assigned_to': assignment.assigned_to.username,
|
'assigned_to': assignment.assigned_to.username,
|
||||||
})
|
})
|
||||||
|
for shipping_voucher in obj.shipping_vouchers.all():
|
||||||
|
timeline.append({
|
||||||
|
'type': 'shipping_voucher',
|
||||||
|
'id': shipping_voucher.id,
|
||||||
|
'timestamp': shipping_voucher.used_at,
|
||||||
|
'voucher': shipping_voucher.voucher,
|
||||||
|
'voucher_type': shipping_voucher.type,
|
||||||
|
})
|
||||||
return sorted(timeline, key=lambda x: x['timestamp'])
|
return sorted(timeline, key=lambda x: x['timestamp'])
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
|
41
core/tickets/tests/v2/test_shipping_vouchers.py
Normal file
41
core/tickets/tests/v2/test_shipping_vouchers.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from django.test import TestCase, Client
|
||||||
|
|
||||||
|
from authentication.models import ExtendedUser
|
||||||
|
from mail.models import Email, EmailAttachment
|
||||||
|
from tickets.models import IssueThread, StateChange, Comment, ShippingVoucher
|
||||||
|
from django.contrib.auth.models import Permission
|
||||||
|
from knox.models import AuthToken
|
||||||
|
|
||||||
|
|
||||||
|
class ShippingVoucherApiTest(TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
self.user = ExtendedUser.objects.create_user('testuser', 'test', 'test')
|
||||||
|
self.user.user_permissions.add(*Permission.objects.all())
|
||||||
|
self.user.save()
|
||||||
|
self.token = AuthToken.objects.create(user=self.user)
|
||||||
|
self.client = Client(headers={'Authorization': 'Token ' + self.token[1]})
|
||||||
|
|
||||||
|
def test_issues_empty(self):
|
||||||
|
response = self.client.get('/api/2/shipping_vouchers/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.json(), [])
|
||||||
|
|
||||||
|
def test_issues_list(self):
|
||||||
|
ShippingVoucher.objects.create(voucher='1234', type='2kg-eu')
|
||||||
|
response = self.client.get('/api/2/shipping_vouchers/')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(response.json()[0]['voucher'], '1234')
|
||||||
|
self.assertEqual(response.json()[0]['used_at'], None)
|
||||||
|
self.assertEqual(response.json()[0]['issue_thread'], None)
|
||||||
|
self.assertEqual(response.json()[0]['type'], '2kg-eu')
|
||||||
|
|
||||||
|
def test_issues_create(self):
|
||||||
|
response = self.client.post('/api/2/shipping_vouchers/', {'voucher': '1234', 'type': '2kg-eu'})
|
||||||
|
self.assertEqual(response.status_code, 201)
|
||||||
|
self.assertEqual(response.json()['voucher'], '1234')
|
||||||
|
self.assertEqual(response.json()['used_at'], None)
|
||||||
|
self.assertEqual(response.json()['issue_thread'], None)
|
Loading…
Reference in a new issue