<commit_before>from datetime import datetime
from decimal import Decimal
import jsonfield

from django.db import models
from django.utils.translation import ugettext as _

from couchdbkit.exceptions import ResourceNotFound
from dimagi.ext.couchdbkit import (
    Document,
    StringProperty,
    DecimalProperty,
    DictProperty,
    BooleanProperty,
    DateTimeProperty,
)
from dimagi.utils.couch.database import iter_docs

# move these too
from corehq.apps.commtrack.exceptions import InvalidProductException, DuplicateProductCodeException
import six
from six.moves import map


class Product(Document):
    """
    A product, e.g. "coartem" or "tylenol"
    """
    domain = StringProperty()
    name = StringProperty()
    unit = StringProperty()
    code_ = StringProperty()  # todo: why the hell is this code_ and not code
    description = StringProperty()
    category = StringProperty()
    program_id = StringProperty()
    cost = DecimalProperty()
    product_data = DictProperty()
    is_archived = BooleanProperty(default=False)
    last_modified = DateTimeProperty()

    @classmethod
    def wrap(cls, data):
        from corehq.apps.groups.models import dt_no_Z_re
        # If "Z" is missing because of the Aug 2014 migration, then add it.
        # cf. Group class
        last_modified = data.get('last_modified')
        if last_modified and dt_no_Z_re.match(last_modified):
            data['last_modified'] += 'Z'
        return super(Product, cls).wrap(data)

    @classmethod
    def save_docs(cls, docs, use_uuids=True, codes_by_domain=None):
        from corehq.apps.commtrack.util import generate_code

        codes_by_domain = codes_by_domain or {}

        def get_codes(domain):
            if domain not in codes_by_domain:
                codes_by_domain[domain] = SQLProduct.objects.filter(domain=domain)\
                    .values_list('code', flat=True).distinct()
            return codes_by_domain[domain]

        for doc in docs:
            doc.last_modified = datetime.utcnow()
            if not doc['code_']:
                doc['code_'] = generate_code(
                    doc['name'],
                    get_codes(doc['domain'])
                )

        super(Product, cls).save_docs(docs, use_uuids)

        domains = {doc['domain'] for doc in docs}
        for domain in domains:
            cls.clear_caches(domain)

    bulk_save = save_docs

    def sync_to_sql(self):
        properties_to_sync = [
            ('product_id', '_id'),
            'domain',
            'name',
            'is_archived',
            ('code', 'code_'),
            'description',
            'category',
            'program_id',
            'cost',
            ('units', 'unit'),
            'product_data',
        ]

        # sync properties to SQL version
        sql_product, _ = SQLProduct.objects.get_or_create(
            product_id=self._id
        )

        for prop in properties_to_sync:
            if isinstance(prop, tuple):
                sql_prop, couch_prop = prop
            else:
                sql_prop = couch_prop = prop

            if hasattr(self, couch_prop):
                setattr(sql_product, sql_prop, getattr(self, couch_prop))

        sql_product.save()

    def save(self, *args, **kwargs):
        """
        Saving a couch version of Product will trigger
        one way syncing to the SQLProduct version of this
        product.
        """
        # mark modified time stamp for selective syncing
        self.last_modified = datetime.utcnow()

        # generate code if user didn't specify one
        if not self.code:
            from corehq.apps.commtrack.util import generate_code
            self.code = generate_code(
                self.name,
                SQLProduct.objects
                    .filter(domain=self.domain)
                    .values_list('code', flat=True)
                    .distinct()
            )

        result = super(Product, self).save(*args, **kwargs)

        self.clear_caches(self.domain)
        self.sync_to_sql()

        return result

    @property
    def code(self):
        return self.code_

    @code.setter
    def code(self, val):
        self.code_ = val.lower() if val else None

    @classmethod
    def clear_caches(cls, domain):
        from casexml.apps.phone.utils import clear_fixture_cache
        from corehq.apps.products.fixtures import ALL_CACHE_PREFIXES
        for prefix in ALL_CACHE_PREFIXES:
            clear_fixture_cache(domain, prefix)

    @classmethod
    def get_by_code(cls, domain, code):
        if not code:
            return None
        try:
            sql_product = SQLProduct.objects.get(domain=domain, code__iexact=code)
        except SQLProduct.DoesNotExist:
            return None
        else:
            return cls.get(sql_product.product_id)

    @classmethod
    def by_domain(cls, domain, wrap=True, include_archived=False):
        queryset = SQLProduct.objects.filter(domain=domain)
        if not include_archived:
            queryset = queryset.filter(is_archived=False)
        return list(queryset.couch_products(wrapped=wrap))

    @classmethod
    def ids_by_domain(cls, domain):
        return list(SQLProduct.objects.filter(domain=domain).product_ids())

    @classmethod
    def count_by_domain(cls, domain):
        """
        Gets count of products in a domain
        """
        # todo: we should add a reduce so we can get this out of couch
        return len(cls.ids_by_domain(domain))<commit_msg>Remove insane unused Product.count_by_domain<commit_after>from datetime import datetime
from decimal import Decimal
import jsonfield

from django.db import models
from django.utils.translation import ugettext as _

from couchdbkit.exceptions import ResourceNotFound
from dimagi.ext.couchdbkit import (
    Document,
    StringProperty,
    DecimalProperty,
    DictProperty,
    BooleanProperty,
    DateTimeProperty,
)
from dimagi.utils.couch.database import iter_docs

# move these too
from corehq.apps.commtrack.exceptions import InvalidProductException, DuplicateProductCodeException
import six
from six.moves import map


class Product(Document):
    """
    A product, e.g. "coartem" or "tylenol"
    """
    domain = StringProperty()
    name = StringProperty()
    unit = StringProperty()
    code_ = StringProperty()  # todo: why the hell is this code_ and not code
    description = StringProperty()
    category = StringProperty()
    program_id = StringProperty()
    cost = DecimalProperty()
    product_data = DictProperty()
    is_archived = BooleanProperty(default=False)
    last_modified = DateTimeProperty()

    @classmethod
    def wrap(cls, data):
        from corehq.apps.groups.models import dt_no_Z_re
        # If "Z" is missing because of the Aug 2014 migration, then add it.
        # cf. Group class
        last_modified = data.get('last_modified')
        if last_modified and dt_no_Z_re.match(last_modified):
            data['last_modified'] += 'Z'
        return super(Product, cls).wrap(data)

    @classmethod
    def save_docs(cls, docs, use_uuids=True, codes_by_domain=None):
        from corehq.apps.commtrack.util import generate_code

        codes_by_domain = codes_by_domain or {}

        def get_codes(domain):
            if domain not in codes_by_domain:
                codes_by_domain[domain] = SQLProduct.objects.filter(domain=domain)\
                    .values_list('code', flat=True).distinct()
            return codes_by_domain[domain]

        for doc in docs:
            doc.last_modified = datetime.utcnow()
            if not doc['code_']:
                doc['code_'] = generate_code(
                    doc['name'],
                    get_codes(doc['domain'])
                )

        super(Product, cls).save_docs(docs, use_uuids)

        domains = {doc['domain'] for doc in docs}
        for domain in domains:
            cls.clear_caches(domain)

    bulk_save = save_docs

    def sync_to_sql(self):
        properties_to_sync = [
            ('product_id', '_id'),
            'domain',
            'name',
            'is_archived',
            ('code', 'code_'),
            'description',
            'category',
            'program_id',
            'cost',
            ('units', 'unit'),
            'product_data',
        ]

        # sync properties to SQL version
        sql_product, _ = SQLProduct.objects.get_or_create(
            product_id=self._id
        )

        for prop in properties_to_sync:
            if isinstance(prop, tuple):
                sql_prop, couch_prop = prop
            else:
                sql_prop = couch_prop = prop

            if hasattr(self, couch_prop):
                setattr(sql_product, sql_prop, getattr(self, couch_prop))

        sql_product.save()

    def save(self, *args, **kwargs):
        """
        Saving a couch version of Product will trigger
        one way syncing to the SQLProduct version of this
        product.
        """
        # mark modified time stamp for selective syncing
        self.last_modified = datetime.utcnow()

        # generate code if user didn't specify one
        if not self.code:
            from corehq.apps.commtrack.util import generate_code
            self.code = generate_code(
                self.name,
                SQLProduct.objects
                    .filter(domain=self.domain)
                    .values_list('code', flat=True)
                    .distinct()
            )

        result = super(Product, self).save(*args, **kwargs)

        self.clear_caches(self.domain)
        self.sync_to_sql()

        return result

    @property
    def code(self):
        return self.code_

    @code.setter
    def code(self, val):
        self.code_ = val.lower() if val else None

    @classmethod
    def clear_caches(cls, domain):
        from casexml.apps.phone.utils import clear_fixture_cache
        from corehq.apps.products.fixtures import ALL_CACHE_PREFIXES
        for prefix in ALL_CACHE_PREFIXES:
            clear_fixture_cache(domain, prefix)

    @classmethod
    def get_by_code(cls, domain, code):
        if not code:
            return None
        try:
            sql_product = SQLProduct.objects.get(domain=domain, code__iexact=code)
        except SQLProduct.DoesNotExist:
            return None
        else:
            return cls.get(sql_product.product_id)

    @classmethod
    def by_domain(cls, domain, wrap=True, include_archived=False):
        queryset = SQLProduct.objects.filter(domain=domain)
        if not include_archived:
            queryset = queryset.filter(is_archived=False)
        return list(queryset.couch_products(wrapped=wrap))

    @classmethod
    def ids_by_domain(cls, domain):
        return list(SQLProduct.objects.filter(domain=domain).product_ids())
{'fraction_non_alphanumeric': 0.08611599297012303, 'fraction_numerical': 0.000739987050226621, 'mean_word_length': 2.184683357879234, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '3077915', 'n_tokens_mistral': 3073, 'n_tokens_neox': 2984, 'n_words': 755}