<commit_before>from dateutil.relativedelta import relativedelta
from django.contrib.postgres.fields import DateRangeField
from django.db import models
from django.db import transaction as db_transaction
from django.db.models.functions import Lower, Upper
from django.utils import formats
from django.utils.datetime_safe import datetime, date
from django_smalluuid.models import uuid_default, SmallUUIDField
from django.conf import settings

from swiftwind.billing_cycle.exceptions import CannotPopulateForDateOutsideExistingCycles
from .cycles import get_billing_cycle


class BillingCycleManager(models.Manager):

    def get_queryset(self):
        queryset = super(BillingCycleManager, self).get_queryset()
        return queryset\
            .annotate(start_date=Lower('date_range'))\
            .annotate(end_date=Upper('date_range'))

    def enactable(self, as_of):
        """Find all billing cycles that should be enacted

        This consists of any billing cycle that has not had transactions created
        for it, and has a start date prior to `as_of`.
        """
        return self.filter(
            transactions_created=False,
            start_date__lte=as_of,
        )

    def as_of(self, date):
        return self.get(start_date__lte=date, end_date__gt=date)


class BillingCycle(models.Model):
    # TODO: Currently does not support changing of billing-cycle type (i.e. monthly/weekly)
    #       once data has been created
    uuid = SmallUUIDField(default=uuid_default(), editable=False)
    date_range = DateRangeField(
        db_index=True,
        help_text='The start and end date of this billing cycle. '
                  'May not overlay with any other billing cycles.'
    )
    transactions_created = models.BooleanField(
        default=False,
        help_text='Have transactions been created for this billing cycle?'
    )

    objects = BillingCycleManager()

    class Meta:
        ordering = ['date_range']

    def __str__(self):
        return 'Cycle starting {}'.format(formats.localize(self.date_range.lower, use_l10n=True))

    def __repr__(self):
        return 'BillingCycle <{}>'.format(self.date_range)

    @classmethod
    def populate(cls):
        """Ensure the next X years of billing cycles exist
        """
        return cls._populate(as_of=date.today(), delete=True)

    @classmethod
    def repopulate(cls):
        """Create the next X years of billing cycles

        Will delete any billing cycles which are in the future
        """
        return cls._populate(as_of=date.today(), delete=False)

    @classmethod
    def _populate(cls, as_of=None, delete=False):
        """Populate the table with billing cycles starting from `as_of`

        Args:
            as_of (date): The date at which to being the populating
            delete (bool): Should future billing cycles be deleted?


        """
        billing_cycle_helper = get_billing_cycle()
        billing_cycles_exist = BillingCycle.objects.exists()

        try:
            current_billing_cycle = BillingCycle.objects.as_of(date=as_of)
        except BillingCycle.DoesNotExist:
            current_billing_cycle = None

        # If no cycles exist then disable the deletion logic
        if not billing_cycles_exist:
            delete = False

        # Cycles exist, but a date has been specified outside of them
        if billing_cycles_exist and not current_billing_cycle:
            raise CannotPopulateForDateOutsideExistingCycles()

        # Omit the current billing cycle if we are deleting (as
        # deleting the current billing cycle will be a Bad Idea)
        omit_current = (current_billing_cycle and delete)

        stop_date = as_of + relativedelta(years=settings.SWIFTWIND_BILLING_CYCLE_YEARS)
        date_ranges = billing_cycle_helper.generate_date_ranges(as_of, stop_date=stop_date, omit_current=omit_current)
        date_ranges = list(date_ranges)<commit_msg>Fixing docs typo<commit_after>from dateutil.relativedelta import relativedelta
from django.contrib.postgres.fields import DateRangeField
from django.db import models
from django.db import transaction as db_transaction
from django.db.models.functions import Lower, Upper
from django.utils import formats
from django.utils.datetime_safe import datetime, date
from django_smalluuid.models import uuid_default, SmallUUIDField
from django.conf import settings

from swiftwind.billing_cycle.exceptions import CannotPopulateForDateOutsideExistingCycles
from .cycles import get_billing_cycle


class BillingCycleManager(models.Manager):

    def get_queryset(self):
        queryset = super(BillingCycleManager, self).get_queryset()
        return queryset\
            .annotate(start_date=Lower('date_range'))\
            .annotate(end_date=Upper('date_range'))

    def enactable(self, as_of):
        """Find all billing cycles that should be enacted

        This consists of any billing cycle that has not had transactions created
        for it, and has a start date prior to `as_of`.
        """
        return self.filter(
            transactions_created=False,
            start_date__lte=as_of,
        )

    def as_of(self, date):
        return self.get(start_date__lte=date, end_date__gt=date)


class BillingCycle(models.Model):
    # TODO: Currently does not support changing of billing-cycle type (i.e. monthly/weekly)
    #       once data has been created
    uuid = SmallUUIDField(default=uuid_default(), editable=False)
    date_range = DateRangeField(
        db_index=True,
        help_text='The start and end date of this billing cycle. '
                  'May not overlay with any other billing cycles.'
    )
    transactions_created = models.BooleanField(
        default=False,
        help_text='Have transactions been created for this billing cycle?'
    )

    objects = BillingCycleManager()

    class Meta:
        ordering = ['date_range']

    def __str__(self):
        return 'Cycle starting {}'.format(formats.localize(self.date_range.lower, use_l10n=True))

    def __repr__(self):
        return 'BillingCycle <{}>'.format(self.date_range)

    @classmethod
    def populate(cls):
        """Ensure the next X years of billing cycles exist
        """
        return cls._populate(as_of=date.today(), delete=True)

    @classmethod
    def repopulate(cls):
        """Create the next X years of billing cycles

        Will delete any billing cycles which are in the future
        """
        return cls._populate(as_of=date.today(), delete=False)

    @classmethod
    def _populate(cls, as_of=None, delete=False):
        """Populate the table with billing cycles starting from `as_of`

        Args:
            as_of (date): The date at which to begin the populating
            delete (bool): Should future billing cycles be deleted?


        """
        billing_cycle_helper = get_billing_cycle()
        billing_cycles_exist = BillingCycle.objects.exists()

        try:
            current_billing_cycle = BillingCycle.objects.as_of(date=as_of)
        except BillingCycle.DoesNotExist:
            current_billing_cycle = None

        # If no cycles exist then disable the deletion logic
        if not billing_cycles_exist:
            delete = False

        # Cycles exist, but a date has been specified outside of them
        if billing_cycles_exist and not current_billing_cycle:
            raise CannotPopulateForDateOutsideExistingCycles()

        # Omit the current billing cycle if we are deleting (as
        # deleting the current billing cycle will be a Bad Idea)
        omit_current = (current_billing_cycle and delete)

        stop_date = as_of + relativedelta(years=settings.SWIFTWIND_BILLING_CYCLE_YEARS)
        date_ranges = billing_cycle_helper.generate_date_ranges(as_of, stop_date=stop_date, omit_current=omit_current)
        date_ranges = list(date_ranges)
{'fraction_non_alphanumeric': 0.0712015257469803, 'fraction_numerical': 0.000508582326764145, 'mean_word_length': 3.0483787956767885, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7129695', 'n_tokens_mistral': 2280, 'n_tokens_neox': 2165, 'n_words': 643}