From 85304fb880771e1384437ce7e05281829bfa50a9 Mon Sep 17 00:00:00 2001 From: Setyo Nugroho Date: Mon, 14 Feb 2022 16:11:54 +0700 Subject: [PATCH] invoice unpaid and finish --- api/serializers.py | 5 ++++- api/views.py | 19 +++++++++++++++++++ core/migrations/0006_alter_invoice_state.py | 18 ++++++++++++++++++ core/migrations/0007_invoice_finish_date.py | 18 ++++++++++++++++++ core/models.py | 16 +++++++++++++++- 5 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 core/migrations/0006_alter_invoice_state.py create mode 100644 core/migrations/0007_invoice_finish_date.py diff --git a/api/serializers.py b/api/serializers.py index a3929d1..1f79ce0 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -43,6 +43,9 @@ class InvoiceSerializer(serializers.ModelSerializer): class SimpleInvoiceSerializer(serializers.ModelSerializer): + subtotal = MoneyField(max_digits=10, decimal_places=0) + subtotal_currency = serializers.CharField(source="subtotal.currency") + class Meta: model = Invoice - fields = ['id', 'start_date', 'end_date', 'state', 'tax', 'total'] + fields = ['id', 'start_date', 'end_date', 'state', 'tax', 'subtotal', 'subtotal_currency', 'total'] diff --git a/api/views.py b/api/views.py index 6c87275..cea9fe5 100644 --- a/api/views.py +++ b/api/views.py @@ -119,6 +119,24 @@ class InvoiceViewSet(viewsets.ModelViewSet): del payload['tenant_id'] handler.create(payload) + @action(detail=True) + def finish(self, request, pk): + invoice = Invoice.objects.filter(id=pk).first() + if invoice.state == Invoice.InvoiceState.UNPAID: + invoice.finish() + + serializer = InvoiceSerializer(invoice) + return Response(serializer.data) + + @action(detail=True) + def rollback_to_unpaid(self, request, pk): + invoice = Invoice.objects.filter(id=pk).first() + if invoice.state == Invoice.InvoiceState.FINISHED: + invoice.rollback_to_unpaid() + + serializer = InvoiceSerializer(invoice) + return Response(serializer.data) + class AdminOverviewViewSet(viewsets.ViewSet): def list(self, request): @@ -179,6 +197,7 @@ class AdminOverviewViewSet(viewsets.ViewSet): return Response(data) + class ProjectOverviewViewSet(viewsets.ViewSet): def list(self, request): return Response({}) diff --git a/core/migrations/0006_alter_invoice_state.py b/core/migrations/0006_alter_invoice_state.py new file mode 100644 index 0000000..8fbdc42 --- /dev/null +++ b/core/migrations/0006_alter_invoice_state.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.6 on 2022-02-13 18:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0005_imageprice_invoiceimage'), + ] + + operations = [ + migrations.AlterField( + model_name='invoice', + name='state', + field=models.IntegerField(choices=[(1, 'In Progress'), (2, 'Unpaid'), (100, 'Finished')]), + ), + ] diff --git a/core/migrations/0007_invoice_finish_date.py b/core/migrations/0007_invoice_finish_date.py new file mode 100644 index 0000000..55d6226 --- /dev/null +++ b/core/migrations/0007_invoice_finish_date.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.6 on 2022-02-13 18:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0006_alter_invoice_state'), + ] + + operations = [ + migrations.AddField( + model_name='invoice', + name='finish_date', + field=models.DateTimeField(blank=True, default=None, null=True), + ), + ] diff --git a/core/models.py b/core/models.py index 92933a0..4d4ed70 100644 --- a/core/models.py +++ b/core/models.py @@ -2,6 +2,7 @@ import math from django.conf import settings from django.db import models +from django.utils import timezone from djmoney.models.fields import MoneyField from djmoney.money import Money @@ -63,11 +64,13 @@ class BillingProject(BaseModel, TimestampMixin): class Invoice(BaseModel, TimestampMixin): class InvoiceState(models.IntegerChoices): IN_PROGRESS = 1 + UNPAID = 2 FINISHED = 100 project = models.ForeignKey('BillingProject', on_delete=models.CASCADE) start_date = models.DateTimeField() end_date = models.DateTimeField(default=None, blank=True, null=True) + finish_date = models.DateTimeField(default=None, blank=True, null=True) state = models.IntegerField(choices=InvoiceState.choices) tax = MoneyField(max_digits=10, decimal_places=0, default=None, blank=True, null=True) total = MoneyField(max_digits=10, decimal_places=0, default=None, blank=True, null=True) @@ -97,12 +100,22 @@ class Invoice(BaseModel, TimestampMixin): return total def close(self, date, tax_percentage): - self.state = Invoice.InvoiceState.FINISHED + self.state = Invoice.InvoiceState.UNPAID self.end_date = date self.tax = tax_percentage * self.subtotal self.total = self.tax + self.subtotal self.save() + def finish(self): + self.state = Invoice.InvoiceState.FINISHED + self.finish_date = timezone.now() + self.save() + + def rollback_to_unpaid(self): + self.state = Invoice.InvoiceState.UNPAID + self.finish_date = None + self.save() + # end region @@ -171,6 +184,7 @@ class InvoiceSnapshot(BaseModel, InvoiceComponentMixin): price_without_allocation = super().price_charged return price_without_allocation * math.ceil(self.space_allocation_gb) + class InvoiceImage(BaseModel, InvoiceComponentMixin): invoice = models.ForeignKey('Invoice', on_delete=models.CASCADE, related_name=labels.LABEL_IMAGES) # Key