diff --git a/core/tickets/admin.py b/core/tickets/admin.py index 20cb83f..d862811 100644 --- a/core/tickets/admin.py +++ b/core/tickets/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from tickets.models import IssueThread, Comment, StateChange, Assignment, ShippingVoucher +from tickets.models import IssueThread, Comment, StateChange class IssueThreadAdmin(admin.ModelAdmin): @@ -15,16 +15,6 @@ class StateChangeAdmin(admin.ModelAdmin): pass -class AssignmentAdmin(admin.ModelAdmin): - pass - - -class ShippingVouchersAdmin(admin.ModelAdmin): - pass - - admin.site.register(IssueThread, IssueThreadAdmin) admin.site.register(Comment, CommentAdmin) admin.site.register(StateChange, StateChangeAdmin) -admin.site.register(Assignment, AssignmentAdmin) -admin.site.register(ShippingVoucher, ShippingVouchersAdmin) diff --git a/core/tickets/api_v2.py b/core/tickets/api_v2.py index f8f746e..cd9cd3e 100644 --- a/core/tickets/api_v2.py +++ b/core/tickets/api_v2.py @@ -13,8 +13,8 @@ from core.settings import MAIL_DOMAIN from mail.models import Email from mail.protocol import send_smtp, make_reply, collect_references from notify_sessions.models import SystemEvent -from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher -from tickets.serializers import IssueSerializer, CommentSerializer, ShippingVoucherSerializer +from tickets.models import IssueThread, Comment, STATE_CHOICES +from tickets.serializers import IssueSerializer, CommentSerializer class IssueViewSet(viewsets.ModelViewSet): @@ -22,11 +22,6 @@ class IssueViewSet(viewsets.ModelViewSet): queryset = IssueThread.objects.all() -class ShippingVoucherViewSet(viewsets.ModelViewSet): - serializer_class = ShippingVoucherSerializer - queryset = ShippingVoucher.objects.all() - - @api_view(['POST']) @permission_classes([IsAuthenticated]) @permission_required('tickets.add_issuethread', raise_exception=True) @@ -118,7 +113,6 @@ def add_comment(request, pk): router = routers.SimpleRouter() router.register(r'tickets', IssueViewSet, basename='issues') -router.register(r'shipping_vouchers', ShippingVoucherViewSet, basename='shipping_vouchers') urlpatterns = ([ re_path(r'^tickets/(?P\d+)/reply/$', reply, name='reply'), diff --git a/core/tickets/migrations/0009_shippingvoucher.py b/core/tickets/migrations/0009_shippingvoucher.py deleted file mode 100644 index a857457..0000000 --- a/core/tickets/migrations/0009_shippingvoucher.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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')), - ], - ), - ] diff --git a/core/tickets/models.py b/core/tickets/models.py index 141cf27..6dd42c3 100644 --- a/core/tickets/models.py +++ b/core/tickets/models.py @@ -1,5 +1,4 @@ from django.db import models -from django.utils import timezone from django_softdelete.models import SoftDeleteModel from authentication.models import ExtendedUser @@ -117,20 +116,3 @@ class Assignment(models.Model): def __str__(self): 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) diff --git a/core/tickets/serializers.py b/core/tickets/serializers.py index 448a902..fe3972e 100644 --- a/core/tickets/serializers.py +++ b/core/tickets/serializers.py @@ -2,7 +2,7 @@ from rest_framework import serializers from authentication.models import ExtendedUser from mail.api_v2 import AttachmentSerializer -from tickets.models import IssueThread, Comment, STATE_CHOICES, ShippingVoucher +from tickets.models import IssueThread, Comment, STATE_CHOICES class CommentSerializer(serializers.ModelSerializer): @@ -28,13 +28,6 @@ class StateSerializer(serializers.Serializer): 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): timeline = serializers.SerializerMethodField() last_activity = serializers.SerializerMethodField() @@ -67,10 +60,7 @@ class IssueSerializer(serializers.ModelSerializer): 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_mail = self.emails.order_by('-timestamp').first().timestamp if self.emails.count() > 0 else 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] + args = [x for x in [last_state_change, last_comment, last_mail] if x is not None] return max(args) except AttributeError: return None @@ -110,14 +100,6 @@ class IssueSerializer(serializers.ModelSerializer): 'timestamp': assignment.timestamp, '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']) def get_queryset(self): diff --git a/core/tickets/tests/v2/test_shipping_vouchers.py b/core/tickets/tests/v2/test_shipping_vouchers.py deleted file mode 100644 index 45fa245..0000000 --- a/core/tickets/tests/v2/test_shipping_vouchers.py +++ /dev/null @@ -1,41 +0,0 @@ -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) diff --git a/web/src/router.js b/web/src/router.js index 7d756e8..3490bc3 100644 --- a/web/src/router.js +++ b/web/src/router.js @@ -15,7 +15,6 @@ import Empty from "@/views/Empty.vue"; import Events from "@/views/admin/Events.vue"; import AccessControl from "@/views/admin/AccessControl.vue"; import {default as BoxesAdmin} from "@/views/admin/Boxes.vue" -import Shipping from "@/views/admin/Shipping.vue"; const routes = [ {path: '/', redirect: '/37C3/items', meta: {requiresAuth: false}}, @@ -70,10 +69,6 @@ const routes = [ path: 'boxes/', name: 'admin_boxes', component: BoxesAdmin, meta: {requiresAuth: true, requiresPermission: 'delete_event'} }, - { - path: 'shipping/', name: 'shipping', component: Shipping, meta: - {requiresAuth: true, requiresPermission: 'delete_event'} - }, ] }, {path: '/user', name: 'user', component: Empty, meta: {requiresAuth: true}}, diff --git a/web/src/store.js b/web/src/store.js index e07c9e0..7ee6614 100644 --- a/web/src/store.js +++ b/web/src/store.js @@ -6,6 +6,7 @@ import * as utf8 from 'utf8'; import {ticketStateColorLookup, ticketStateIconLookup, http} from "@/utils"; import sharedStatePlugin from "@/shared-state-plugin"; import persistentStatePlugin from "@/persistent-state-plugin"; +import {triggerRef} from "vue"; const store = createStore({ state: { @@ -19,8 +20,6 @@ const store = createStore({ users: [], groups: [], state_options: [], - shippingVouchers: [], - lastEvent: '37C3', lastUsed: {}, remember: false, @@ -41,22 +40,12 @@ const store = createStore({ users: 0, groups: 0, states: 0, - shippingVouchers: 0, }, persistent_loaded: false, shared_loaded: false, afterInitHandlers: [], showAddBoxModal: false, - - shippingVoucherTypes: { - '2kg-de': '2kg Paket (DE)', - '5kg-de': '5kg Paket (DE)', - '10kg-de': '10kg Paket (DE)', - '2kg-eu': '2kg Paket (EU)', - '5kg-eu': '5kg Paket (EU)', - '10kg-eu': '10kg Paket (EU)', - } }, getters: { route: state => router.currentRoute.value, @@ -86,12 +75,6 @@ const store = createStore({ } } }, - availableShippingVoucherTypes: state => { - return Object.keys(state.shippingVoucherTypes).map(key => { - var count = state.shippingVouchers.filter(voucher => voucher.type === key && voucher.issue_thread === null).length; - return {id: key, count: count, name: state.shippingVoucherTypes[key]}; - }); - }, layout: (state, getters) => { if (router.currentRoute.value.query.layout) return router.currentRoute.value.query.layout; @@ -156,6 +139,7 @@ const store = createStore({ updateTicket(state, updatedTicket) { const ticket = state.tickets.filter(({id}) => id === updatedTicket.id)[0]; Object.assign(ticket, updatedTicket); + //triggerRef(state.tickets); state.tickets = [...state.tickets]; }, replaceUsers(state, users) { @@ -214,10 +198,6 @@ const store = createStore({ setThumbnail(state, {url, data}) { state.thumbnailCache[url] = data; }, - setShippingVouchers(state, codes) { - state.shippingVouchers = codes; - state.fetchedData = {...state.fetchedData, shippingVouchers: Date.now()}; - }, }, actions: { async login({commit}, {username, password, remember}) { @@ -432,33 +412,6 @@ const store = createStore({ async updateTicketPartial({commit, state}, {id, ...ticket}) { const {data, success} = await http.patch(`/2/tickets/${id}/`, ticket, state.user.token); commit('updateTicket', data); - }, - async fetchShippingVouchers({commit, state}) { - if (!state.user.token) return; - if (state.fetchedData.shippingVouchers > Date.now() - 1000 * 60 * 60 * 24) return; - const {data, success} = await http.get('/2/shipping_vouchers/', state.user.token); - if (data && success) { - commit('setShippingVouchers', data); - } - }, - async createShippingVoucher({dispatch, state}, code) { - const {data, success} = await http.post('/2/shipping_vouchers/', code, state.user.token); - if (data && success) { - state.fetchedData.shippingVouchers = 0; - dispatch('fetchShippingVouchers'); - } - }, - async claimShippingVoucher({dispatch, state}, {ticket, shipping_voucher_type}) { - const id = state.shippingVouchers.filter(voucher => voucher.type === shipping_voucher_type && voucher.issue_thread === null)[0].id; - const { - data, - success - } = await http.patch(`/2/shipping_vouchers/${id}/`, {issue_thread: ticket}, state.user.token); - if (data && success) { - state.fetchedData.shippingVouchers = 0; - state.fetchedData.tickets = 0; - await Promise.all([dispatch('loadTickets'), dispatch('fetchShippingVouchers')]); - } } }, plugins: [ @@ -474,7 +427,7 @@ const store = createStore({ ] }), sharedStatePlugin({ - debug: false, + debug: true, isLoadedKey: "shared_loaded", clearingMutation: "logout", afterInit: "afterSharedInit", @@ -487,7 +440,6 @@ const store = createStore({ "groups", "loadedBoxes", "loadedItems", - "shippingVouchers", ], watch: [ "test", @@ -498,7 +450,6 @@ const store = createStore({ "groups", "loadedBoxes", "loadedItems", - "shippingVouchers", ], mutations: [ //"replaceTickets", diff --git a/web/src/views/Ticket.vue b/web/src/views/Ticket.vue index e92fb8e..b4d1e0e 100644 --- a/web/src/views/Ticket.vue +++ b/web/src/views/Ticket.vue @@ -13,6 +13,10 @@ Delete + + + Copy DHL contact to clipboard +
- - - -
- @@ -55,21 +41,15 @@ - - \ No newline at end of file