Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
wbcrm / crm / models / dynamic_fields.py
Size: Mime:
import logging
import sys
from enum import Enum

from django.contrib.postgres.fields import ArrayField, JSONField
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models
from django.db.models import Q
from django.db.models.signals import (m2m_changed, post_delete, post_save,
                                      pre_save)
from django.dispatch import receiver
from django_fsm import FSMField, transition
from django_fsm_log.decorators import fsm_log_by, fsm_log_description
from dynamic_preferences.registries import global_preferences_registry
from slugify import slugify

import crm

class Linkage(Enum):
    PERSON = 'PERSON'
    COMPANY = 'COMPANY'
    BOTH = 'BOTH'


class DynamicField(models.Model):
    linkage_choices = (
        (Linkage.PERSON.value, 'Person'),
        (Linkage.COMPANY.value, 'Company'),
        (Linkage.BOTH.value, 'Both'),
    )
    linkage = models.CharField(max_length=10, choices=linkage_choices, default=Linkage.BOTH.value)
    title = models.CharField(max_length=64)
    key = models.CharField(max_length=64, null=True, blank=True, unique=True)

    class Meta:
        abstract = True

    def get_key(self):
        return self.key

    def get_empty_dict(self):
        return {
            'title': self.title,
            'field_type': self.get_field_type(),
            'content': '',
            'class_name': self.__class__.__name__,
        }

    def save(self, *args, **kwargs):
        self.key = slugify(self.title)
        old_self = None
        if self.id:
            old_self = self.__class__.objects.get(id=self.id)
        super().save(*args, **kwargs)
        for entry in crm.models.entries.Entry.objects.all():
            entry.update_or_create_additional_fields(self, old_self)
            entry.save()

    def delete(self, *args, **kwargs):
        key = self.get_key()
        super().delete(*args, **kwargs)
        for entry in crm.models.entries.Entry.objects.all():
            entry.delete_additional_fields(additional_field_key=key)
            entry.save()

    def __str__(self):
        return '%s' % (self.key)

    @classmethod
    def get_field_for_key(cls, key):
        try:
            return DynamicCharField.objects.get(key=key)
        except DynamicCharField.DoesNotExist:
            pass
        try:
            return DynamicRangeField.objects.get(key=key)
        except DynamicRangeField.DoesNotExist:
            pass
        try:
            return DynamicChoiceField.objects.get(key=key)
        except DynamicChoiceField.DoesNotExist:
            pass

        return None

    @classmethod
    def validate_field_for_key(cls, key, value):
        instance = cls.get_field_for_key(key=key)
        return instance.validate_field(value)

    @classmethod
    def get_field_count_for_entry(cls, entry):
        count = 0
        count += DynamicCharField.objects.filter(Q(linkage=Linkage.BOTH.value) | Q(linkage=entry.get_linkage_value())).count()
        count += DynamicRangeField.objects.filter(Q(linkage=Linkage.BOTH.value) | Q(linkage=entry.get_linkage_value())).count()
        count += DynamicChoiceField.objects.filter(Q(linkage=Linkage.BOTH.value) | Q(linkage=entry.get_linkage_value())).count()
        return count


class DynamicCharField(DynamicField):
    def get_field_type(self):
        return 'CharField'

    def validate_field(self, value):
        return (True, '', value)


class DynamicRangeField(DynamicField):
    range_min = models.FloatField()
    range_max = models.FloatField()

    def get_empty_dict(self):
        empty_dict = super().get_empty_dict()
        empty_dict['range_min'] = self.range_min
        empty_dict['range_max'] = self.range_max
        return empty_dict

    def get_field_type(self):
        return 'RangeField'

    def validate_field(self, value):
        try:
            value = float(value)
        except ValueError:
            return (False, 'Not a number.', None)

        if value > self.range_max or value < self.range_min:
            return (False, 'Out of range.', None)
        return (True, '', value)


class DynamicChoiceField(DynamicField):
    choices = ArrayField(models.CharField(max_length=32))

    def get_empty_dict(self):
        empty_dict = super().get_empty_dict()
        empty_dict['choices'] = self.choices
        return empty_dict

    def get_field_type(self):
        return 'ChoiceField'

    def validate_field(self, value):
        if str(value) in self.choices:
            return (True, '', str(value))
        else:
            return (False, 'Not a valid choice.', None)