From d47c94ba8476c10cc6e599c8d51c4bf09d82c606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Floure?= Date: Fri, 8 May 2020 10:07:44 +0200 Subject: [PATCH] Implement non-destructive order updates --- uncloud_pay/models.py | 1 + uncloud_pay/serializers.py | 2 +- uncloud_pay/views.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/uncloud_pay/models.py b/uncloud_pay/models.py index 1d16eab..c2b7378 100644 --- a/uncloud_pay/models.py +++ b/uncloud_pay/models.py @@ -827,6 +827,7 @@ class Order(models.Model): editable=False) billing_address = models.ForeignKey(BillingAddress, on_delete=models.CASCADE) description = models.TextField() + replaced_by = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True) # TODO: enforce ending_date - starting_date to be larger than recurring_period. creation_date = models.DateTimeField(auto_now_add=True) diff --git a/uncloud_pay/serializers.py b/uncloud_pay/serializers.py index 1d7dcdd..a1ea39b 100644 --- a/uncloud_pay/serializers.py +++ b/uncloud_pay/serializers.py @@ -71,7 +71,7 @@ class OrderSerializer(serializers.ModelSerializer): class Meta: model = Order fields = ['uuid', 'owner', 'description', 'creation_date', 'starting_date', 'ending_date', - 'bill', 'recurring_period', 'recurring_price', 'one_time_price'] + 'bill', 'recurring_period', 'recurring_price', 'one_time_price', 'replaced_by'] ### diff --git a/uncloud_pay/views.py b/uncloud_pay/views.py index 18b76e4..283d04b 100644 --- a/uncloud_pay/views.py +++ b/uncloud_pay/views.py @@ -13,6 +13,7 @@ from hardcopy import bytestring_to_pdf from django.core.files.temp import NamedTemporaryFile from django.http import FileResponse from django.template.loader import render_to_string +from copy import deepcopy import json import logging @@ -304,6 +305,7 @@ class AdminBillViewSet(BillViewSet): class AdminOrderViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, + mixins.UpdateModelMixin, viewsets.GenericViewSet): serializer_class = OrderSerializer permission_classes = [permissions.IsAdminUser] @@ -314,6 +316,32 @@ class AdminOrderViewSet(mixins.ListModelMixin, def get_queryset(self): return Order.objects.all() + # Updates create a new order and terminate the 'old' one. + @transaction.atomic + def update(self, request, *args, **kwargs): + order = self.get_object() + partial = kwargs.pop('partial', False) + serializer = self.get_serializer(order, data=request.data, partial=partial) + serializer.is_valid(raise_exception=True) + + # Clone existing order for replacement. + replacing_order = deepcopy(order) + + # Yes, that's how you make a new entry in DB: + # https://docs.djangoproject.com/en/3.0/topics/db/queries/#copying-model-instances + replacing_order.pk = None + + for attr, value in serializer.validated_data.items(): + setattr(replacing_order, attr, value) + + # Save replacing order and terminate 'previous' one. + replacing_order.save() + order.replaced_by = replacing_order + order.save() + order.terminate() + + return Response(replacing_order) + @action(detail=True, methods=['post']) def terminate(self, request, pk): order = self.get_object()