<s> from django import forms <EOL> from django . db import models <EOL> from django . db . models import Q , Count <EOL> from django . contrib . contenttypes . models import ContentType <EOL> from django . utils . translation import ugettext_lazy as _ <EOL> from sellmo . core import chaining <EOL> from sellmo . core . loading import load <EOL> from sellmo . core import indexing <EOL> from sellmo . apps . pricing import Price <EOL> from sellmo . contrib . attribute . query import product_q <EOL> from sellmo . utils . text import call_or_format <EOL> import sellmo . apps . purchase as _purchase <EOL> import sellmo . apps . product as _product <EOL> import sellmo . apps . cart as _cart <EOL> import sellmo . contrib . attribute as _attribute <EOL> import sellmo . contrib . variation as _variation <EOL> from . helpers import ProductAttributeHelper <EOL> from . constants import VARIATION_CHOICE_FORMAT , VARIATION_VALUE_SEPERATOR <EOL> class AddToCartForm ( _cart . forms . AddToCartForm ) : <EOL> @ classmethod <EOL> @ chaining . define <EOL> def variation_choice ( cls , variation , attributes = None , ** kwargs ) : <EOL> result = ( yield chaining . forward ) . result <EOL> if result is not None : <EOL> return <EOL> variant = variation . variant . downcast ( ) <EOL> price_adjustment = None <EOL> if variant . is_variant : <EOL> a = Price . calculate ( product = variant , raw = True ) <EOL> b = Price . calculate ( product = variant . product , raw = True ) <EOL> price_adjustment = Price ( <NUM_LIT:0> ) <EOL> if a is not None and b is not None : <EOL> price_adjustment = ( a - b ) <EOL> values = variation . values . all ( ) . order_by ( '<STR_LIT>' ) <EOL> if attributes is not None : <EOL> values = values . filter ( attribute__in = attributes ) <EOL> values = VARIATION_VALUE_SEPERATOR . join ( <EOL> [ unicode ( value ) for value in values ] <EOL> ) <EOL> yield call_or_format ( <EOL> VARIATION_CHOICE_FORMAT , <EOL> variation = variation , <EOL> variant = variant , <EOL> values = values , <EOL> price_adjustment = price_adjustment <EOL> ) <EOL> @ classmethod <EOL> def factory ( <EOL> cls , <EOL> data = None , <EOL> product = None , <EOL> variations = None , <EOL> hide_variation_field = False , <EOL> ** kwargs <EOL> ) : <EOL> Form = super ( AddToCartForm , cls ) . factory ( <EOL> data = data , <EOL> product = product , <EOL> variations = variations , <EOL> hide_variation_field = hide_variation_field , <EOL> ** kwargs <EOL> ) <EOL> if variations is None : <EOL> if data is not None and '<STR_LIT>' in data : <EOL> keys = data [ '<STR_LIT>' ] . split ( '<STR_LIT:|>' ) <EOL> variations = _variation . models . Variation . objects . filter ( <EOL> pk__in = keys ) <EOL> elif product is not None : <EOL> variations = product . get_variations ( ) <EOL> if variations is None or variations . count ( ) == <NUM_LIT:0> : <EOL> return AddToCartForm <EOL> if not hide_variation_field : <EOL> attributes = _attribute . models . Attribute . objects . which_variate_variations ( <EOL> variations ) <EOL> if attributes is not None and attributes . count ( ) == <NUM_LIT:1> : <EOL> label = unicode ( attributes [ <NUM_LIT:0> ] ) <EOL> else : <EOL> label = _ ( "<STR_LIT>" ) <EOL> attrs = { <EOL> '<STR_LIT>' : forms . CharField ( <EOL> initial = '<STR_LIT:|>' . join ( <EOL> [ <EOL> variation . pk for variation in variations <EOL> ] <EOL> ) , <EOL> widget = forms . HiddenInput <EOL> ) <EOL> } <EOL> if not hide_variation_field : <EOL> attrs [ '<STR_LIT>' ] = forms . ChoiceField ( <EOL> initial = variations [ : <NUM_LIT:1> ] [ <NUM_LIT:0> ] . pk , <EOL> label = label , <EOL> choices = [ <EOL> ( <EOL> obj . id , AddToCartForm . variation_choice ( <EOL> obj , attributes <EOL> ) <EOL> ) for obj in variations <EOL> ] <EOL> ) <EOL> else : <EOL> attrs [ '<STR_LIT>' ] = forms . CharField ( <EOL> initial = variations [ : <NUM_LIT:1> ] [ <NUM_LIT:0> ] . pk , <EOL> widget = forms . HiddenInput <EOL> ) <EOL> Form = type ( '<STR_LIT>' , ( AddVariationToCartForm , Form ) , attrs ) <EOL> return Form <EOL> class AddVariationToCartForm ( forms . Form ) : <EOL> def get_purchase_args ( self ) : <EOL> args = super ( AddVariationToCartForm , self ) . get_purchase_args ( ) <EOL> try : <EOL> variation = _variation . models . Variation . objects . get ( <EOL> pk = self . cleaned_data [ '<STR_LIT>' ] <EOL> ) <EOL> except _variation . models . Variation . DoesNotExist : <EOL> raise PurchaseInvalid ( ) <EOL> args [ '<STR_LIT>' ] = variation . variant . downcast ( ) <EOL> args [ '<STR_LIT>' ] = variation <EOL> return args <EOL> _cart . forms . AddToCartForm = AddToCartForm <EOL> @ load ( before = '<STR_LIT>' ) <EOL> def load_model ( ) : <EOL> class Purchase ( _purchase . models . Purchase ) : <EOL> @ classmethod <EOL> def factory ( cls , variation = None , ** kwargs ) : <EOL> if variation is not None : <EOL> return _variation . models . VariationPurchase <EOL> return super ( Purchase , cls ) . factory ( variation = variation , ** kwargs ) <EOL> class Meta ( _purchase . models . Purchase . Meta ) : <EOL> abstract = True <EOL> class PurchaseQuerySet ( _purchase . models . PurchaseQuerySet ) : <EOL> def mergeable_with ( self , purchase ) : <EOL> purchase = purchase . downcast ( ) <EOL> queryset = self <EOL> if isinstance ( purchase , _variation . models . VariationPurchase ) : <EOL> queryset = queryset . filter ( <EOL> productpurchase__variationpurchase__variation_key = <EOL> purchase . variation_key <EOL> ) <EOL> queryset = super ( PurchaseQuerySet , <EOL> queryset ) . mergeable_with ( purchase ) <EOL> return queryset <EOL> _purchase . models . Purchase = Purchase <EOL> _purchase . models . PurchaseQuerySet = PurchaseQuerySet <EOL> @ load ( before = '<STR_LIT>' ) <EOL> def load_model ( ) : <EOL> class ProductQuerySet ( _product . models . ProductQuerySet ) : <EOL> def variants ( self , exclude = False ) : <EOL> content_types = ContentType . objects . get_for_models ( <EOL> * _variation . models . Variant . SUBTYPES ) <EOL> content_types = content_types . values ( ) <EOL> if exclude : <EOL> queryset = self . exclude ( content_type__in = content_types ) <EOL> else : <EOL> queryset = self . filter ( content_type__in = content_types ) <EOL> return queryset <EOL> class Product ( _product . models . Product ) : <EOL> is_variant = False <EOL> variations_synced = models . BooleanField ( default = False , editable = False ) <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> super ( Product , self ) . __init__ ( * args , ** kwargs ) <EOL> self . attributes = ProductAttributeHelper ( self ) <EOL> def get_variations ( self ) : <EOL> if self . is_variant : <EOL> variations = _variation . models . Variation . objects . for_product ( <EOL> self . product ) . filter ( variant = self ) <EOL> else : <EOL> variations = _variation . models . Variation . objects . for_product ( self ) <EOL> return variations . polymorphic_select_related ( '<STR_LIT>' ) <EOL> def save ( self , * args , ** kwargs ) : <EOL> super ( Product , self ) . save ( * args , ** kwargs ) <EOL> downcasted = self . downcast ( ) <EOL> if ( <EOL> hasattr ( downcasted , '<STR_LIT>' ) and <EOL> downcasted . variants . count ( ) > <NUM_LIT:0> <EOL> ) : <EOL> for variant in downcasted . variants . all ( ) : <EOL> variant . save ( ) <EOL> class Meta ( _product . models . Product . Meta ) : <EOL> abstract = True <EOL> _product . models . Product = Product <EOL> _product . models . ProductQuerySet = ProductQuerySet <EOL> @ load ( before = '<STR_LIT>' ) <EOL> def load_model ( ) : <EOL> class AttributeQuerySet ( _attribute . models . AttributeQuerySet ) : <EOL> def for_product_or_variants_of ( self , product ) : <EOL> return ( <EOL> self . filter ( <EOL> Q ( values__product = product ) | Q ( <EOL> values__base_product = product <EOL> ) <EOL> ) . distinct ( ) <EOL> ) <EOL> def which_variate_product ( self , product ) : <EOL> return self . filter ( <EOL> Q ( variates = True ) & ( <EOL> Q ( values__base_product = product ) | Q ( <EOL> values__product = product <EOL> ) & Q ( values__variates = True ) <EOL> ) <EOL> ) . distinct ( ) <EOL> def which_variate_variations ( self , variations ) : <EOL> attributes = _attribute . models . Attribute . objects . none ( ) <EOL> num_variations = variations . count ( ) <EOL> if num_variations > <NUM_LIT:1> : <EOL> values = ( <EOL> _attribute . models . Value . objects . smart_values ( <EOL> '<STR_LIT>' , '<STR_LIT:value>' <EOL> ) . annotate ( num = Count ( '<STR_LIT>' ) ) . filter ( <EOL> variations = variations , <EOL> num__lt = num_variations <EOL> ) . order_by ( ) <EOL> ) <EOL> attributes = _attribute . models . Attribute . objects . filter ( <EOL> pk__in = set ( [ value [ '<STR_LIT>' ] . pk for value in values ] ) <EOL> ) <EOL> return attributes <EOL> class Attribute ( _attribute . models . Attribute ) : <EOL> variates = models . BooleanField ( <EOL> default = False , <EOL> verbose_name = _ ( "<STR_LIT>" ) <EOL> ) <EOL> groups = models . BooleanField ( default = False , verbose_name = _ ( "<STR_LIT>" ) ) <EOL> def save ( self , * args , ** kwargs ) : <EOL> old = None <EOL> if self . pk : <EOL> old = _attribute . models . Attribute . objects . get ( pk = self . pk ) <EOL> super ( Attribute , self ) . save ( * args , ** kwargs ) <EOL> if self . variates or old and old . variates : <EOL> products = _product . models . Product . objects . filter ( <EOL> product_q ( <EOL> attribute = self , <EOL> through = '<STR_LIT>' <EOL> ) <EOL> ) <EOL> _variation . models . Variation . objects . invalidate ( <EOL> products = products <EOL> ) <EOL> class Meta ( _attribute . models . Attribute . Meta ) : <EOL> abstract = True <EOL> _attribute . models . Attribute = Attribute <EOL> _attribute . models . AttributeQuerySet = AttributeQuerySet <EOL> @ load ( before = '<STR_LIT>' ) <EOL> def load_model ( ) : <EOL> class ValueQuerySet ( _attribute . models . ValueQuerySet ) : <EOL> def for_product_or_variants_of ( self , product ) : <EOL> q = Q ( product = product ) | Q ( base_product = product ) <EOL> return self . filter ( q ) <EOL> def which_variate_product ( self , product ) : <EOL> return self . filter ( <EOL> Q ( attribute__variates = True ) & ( <EOL> Q ( base_product = product ) | Q ( <EOL> product = product <EOL> ) & Q ( variates = True ) <EOL> ) <EOL> ) <EOL> class ValueManager ( _attribute . models . ValueManager ) : <EOL> def get_by_natural_key ( <EOL> self , <EOL> attribute , <EOL> product , <EOL> value , <EOL> variates , <EOL> queryset = None <EOL> ) : <EOL> queryset = self . filter ( variates = variates ) <EOL> return super ( ValueManager , <EOL> self ) . get_by_natural_key ( attribute , <EOL> product , <EOL> value , <EOL> queryset = queryset ) <EOL> class Value ( _attribute . models . Value ) : <EOL> base_product = models . ForeignKey ( <EOL> '<STR_LIT>' , <EOL> db_index = True , <EOL> null = True , <EOL> blank = True , <EOL> editable = False , <EOL> related_name = '<STR_LIT>' <EOL> ) <EOL> variates = models . BooleanField ( default = False , editable = False ) <EOL> def natural_key ( self ) : <EOL> return super ( Value , self ) . natural_key ( ) + ( self . variates , ) <EOL> class Meta ( _attribute . models . Value . Meta ) : <EOL> abstract = True <EOL> _attribute . models . Value = Value <EOL> _attribute . models . ValueQuerySet = ValueQuerySet <EOL> _attribute . models . ValueManager = ValueManager <EOL> @ load ( before = '<STR_LIT>' ) <EOL> def load_model ( ) : <EOL> class ProductRelatable ( _product . models . ProductRelatable ) : <EOL> @ classmethod <EOL> def get_limit_choices_to ( cls ) : <EOL> return Q ( <EOL> content_type__in = ContentType . objects . get_for_models ( <EOL> * _product . models . Product . SUBTYPES <EOL> ) . values ( ) <EOL> ) <EOL> def get_related_products ( self ) : <EOL> products = super ( ProductRelatable , self ) . get_related_products ( ) <EOL> products = products . variants ( exclude = True ) <EOL> return products <EOL> class Meta ( _product . models . ProductRelatable . Meta ) : <EOL> abstract = True <EOL> _product . models . ProductRelatable = ProductRelatable <EOL> @ load ( after = '<STR_LIT>' ) <EOL> @ load ( before = '<STR_LIT>' ) <EOL> def load_index ( ) : <EOL> class ProductIndex ( _product . indexes . ProductIndex ) : <EOL> variation = indexing . ModelField ( <EOL> _variation . models . Variation , <EOL> varieties = ( lambda document : list ( _variation . models . Variation . objects . for_product ( document , allow_sync = False ) ) + [ None ] ) <EOL> ) <EOL> def get_queryset ( self ) : <EOL> queryset = super ( ProductIndex , self ) . get_queryset ( ) <EOL> return queryset . variants ( exclude = True ) <EOL> def get_attribute_value ( self , <EOL> document , <EOL> attribute , <EOL> variation = None , <EOL> ** variety ) : <EOL> variation = variation or document <EOL> value = variation . attributes [ attribute . key ] <EOL> value = attribute . get_type ( ) . prep_index_value ( value ) <EOL> return value <EOL> def has_attribute ( self , <EOL> document , <EOL> attribute , <EOL> variation = None , <EOL> ** variety ) : <EOL> variation = variation or document <EOL> return attribute in variation . attributes <EOL> _product . indexes . ProductIndex = ProductIndex </s>
