diff --git a/api/views.py b/api/views.py index 2a01151..36ca225 100644 --- a/api/views.py +++ b/api/views.py @@ -1,3 +1,5 @@ +from typing import Dict, Iterable + import dateutil.parser import pytz from django.db import transaction @@ -7,11 +9,13 @@ from rest_framework.decorators import action from rest_framework.response import Response from api.serializers import InvoiceSerializer, SimpleInvoiceSerializer -from core.component import component +from core.component import component, labels from core.component.component import INVOICE_COMPONENT_MODEL from core.exception import PriceNotFound from core.models import Invoice, BillingProject -from core.utils.dynamic_setting import get_dynamic_settings, get_dynamic_setting, set_dynamic_setting, BILLING_ENABLED +from core.utils.dynamic_setting import get_dynamic_settings, get_dynamic_setting, set_dynamic_setting, BILLING_ENABLED, \ + INVOICE_TAX +from core.utils.model_utils import InvoiceComponentMixin def get_generic_model_view_set(model): @@ -88,10 +92,27 @@ class InvoiceViewSet(viewsets.ModelViewSet): @action(detail=False, methods=['POST']) def disable_billing(self, request): set_dynamic_setting(BILLING_ENABLED, False) + active_invoices = Invoice.objects.filter(state=Invoice.InvoiceState.IN_PROGRESS).all() + for active_invoice in active_invoices: + self._close_active_invoice(active_invoice, timezone.now(), get_dynamic_setting(INVOICE_TAX)) + return Response({ "status": "success" }) + def _close_active_invoice(self, active_invoice: Invoice, close_date, tax_percentage): + active_components_map: Dict[str, Iterable[InvoiceComponentMixin]] = {} + + for label in labels.INVOICE_COMPONENT_LABELS: + active_components_map[label] = getattr(active_invoice, label).filter(end_date=None).all() + + # Close Invoice Component + for active_component in active_components_map[label]: + active_component.close(close_date) + + # Finish current invoice + active_invoice.close(close_date, tax_percentage) + @action(detail=False, methods=['POST']) def reset_billing(self, request): self.handle_reset_billing() @@ -135,7 +156,7 @@ class InvoiceViewSet(viewsets.ModelViewSet): # create not accepting tenant_id, delete it del payload['tenant_id'] - handler.create(payload) + handler.create(payload, fallback_price=True) @transaction.atomic def handle_reset_billing(self): diff --git a/core/models.py b/core/models.py index 5153770..86fa9da 100644 --- a/core/models.py +++ b/core/models.py @@ -27,7 +27,7 @@ class DynamicSetting(BaseModel): # region Pricing class FlavorPrice(BaseModel, TimestampMixin, PriceMixin): - flavor_id = models.CharField(max_length=256) + flavor_id = models.CharField(max_length=256, unique=True, blank=False) class FloatingIpsPrice(BaseModel, TimestampMixin, PriceMixin): @@ -36,7 +36,7 @@ class FloatingIpsPrice(BaseModel, TimestampMixin, PriceMixin): class VolumePrice(BaseModel, TimestampMixin, PriceMixin): - volume_type_id = models.CharField(max_length=256) + volume_type_id = models.CharField(max_length=256, unique=True, blank=False) class RouterPrice(BaseModel, TimestampMixin, PriceMixin): diff --git a/core/utils/dynamic_setting.py b/core/utils/dynamic_setting.py index ddb6c20..2374a30 100644 --- a/core/utils/dynamic_setting.py +++ b/core/utils/dynamic_setting.py @@ -4,10 +4,20 @@ from core.models import DynamicSetting BILLING_ENABLED = "billing_enabled" INVOICE_TAX = "invoice_tax" +COMPANY_NAME = "company_name" +COMPANY_LOGO = "company_logo" +COMPANY_ADDRESS = "company_address" +EMAIL_ADMIN = "email_admin" +EMAIL_NOTIFICATION = "email_notification" DEFAULTS = { BILLING_ENABLED: False, - INVOICE_TAX: 11 + INVOICE_TAX: 11, + COMPANY_NAME: "BTECH DEV", + COMPANY_LOGO: '', + COMPANY_ADDRESS: '', + EMAIL_ADMIN: '', + EMAIL_NOTIFICATION: '', } @@ -55,6 +65,7 @@ def set_dynamic_setting(key, value): inserted_value = value data_type = DynamicSetting.DataType.STR else: + print("SETTING TAB = ", type(value)) raise ValueError("Type not supported") DynamicSetting.objects.update_or_create(key=key, defaults={