3
6\F                 @   sP  d dl Z d dlZd dlmZmZ d dlmZ d dlmZ d dlm	Z	 d dl
mZ d dlmZ d dlmZmZ d d	lmZ d d
lmZ d dlmZ d dlmZmZ d dlmZ d dlmZ d dlmZ d dl m!Z! d dl"m#Z$ d dl"m%Z%m&Z& d dl'm(Z( d dl)m*Z*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1m2Z2 d dl3m4Z4 d dl5m6Z6 e*ddZ7e*ddZ8e*ddZ9e*dd Z:G d!d" d"ej;Z<G d#d$ d$e(Z=G d%d& d&ej;Z>G d'd( d(ej;Z?G d)d* d*ej;Z@G d+d, d,ej;ZAG d-d. d.ej;ZBG d/d0 d0ej;ZCG d1d2 d2ej;ZDG d3d4 d4ej;ZEG d5d6 d6eFZGG d7d8 d8ej;ZHd d9lIT dS ):    N)datedatetime)settings)GenericForeignKey)ContentType)find)cache)ImproperlyConfiguredValidationError)File)RegexValidator)models)CountSum)reverse)cached_property)
strip_tags)	mark_safe)gettext_lazy)get_languagepgettext_lazy)MP_Node)	get_class	get_model)slugify)non_python_keyword)AutoSlugFieldNullCharField)	SlugField)Userzcatalogue.managersBrowsableProductManagerProductQuerySetzcatalogue.product_attributesProductAttributesContainerzpartner.strategySelectorc               @   s   e Zd ZdZejedddZeedddddZ	ej
ed	dd
Zej
eddd
ZejddeddZG dd dZdd Zedd ZdS )AbstractProductClassaD  
    Used for defining options and attributes for a subset of products.
    E.g. Books, DVDs and Toys. A product can only belong to one product class.

    At least one product class must be created when setting up a new
    Oscar deployment.

    Not necessarily equivalent to top-level categories but usually will be.
    Name   )
max_lengthSlugTname)r'   uniquepopulate_fromzRequires shipping?)defaultzTrack stock levels?zcatalogue.OptionOptions)blankverbose_namec               @   s*   e Zd ZdZdZdgZedZedZdS )zAbstractProductClass.MetaT	cataloguer)   zProduct classzProduct classesN)	__name__
__module____qualname__abstract	app_labelordering_r/   verbose_name_plural r9   r9   ?/var/www/html/oscar2019/oscar/apps/catalogue/abstract_models.pyMetaC   s
   r;   c             C   s   | j S )N)r)   )selfr9   r9   r:   __str__J   s    zAbstractProductClass.__str__c             C   s
   | j j S )N)
attributesexists)r<   r9   r9   r:   has_attributesM   s    z#AbstractProductClass.has_attributesN)r1   r2   r3   __doc__r   	CharFieldr7   r)   r   slugBooleanFieldrequires_shippingZtrack_stockManyToManyFieldoptionsr;   r=   propertyr@   r9   r9   r9   r:   r$   %   s   	
r$   c                   s   e Zd ZdZd)ZejeddddZej	ed	dd
Z
ejeddddddZeeddddZdZdZdd Zedd Zedd Zdd Z fddZdd Zdd Zdd  Zd!d" ZG d#d$ d$Zd%d& Zd'd( Z  ZS )*AbstractCategoryz
    A product category. Merely used for navigational purposes; has no
    effects on business logic.

    Uses django-treebeard.
    pkpathdepthr%      T)r'   db_indexDescription)r.   Image
categories)	upload_tor.   nullr'   r(   /z > c             C   s   | j S )N)	full_name)r<   r9   r9   r:   r=   g   s    zAbstractCategory.__str__c             C   s   dd | j  D }| jj|S )aR  
        Returns a string representation of the category and it's ancestors,
        e.g. 'Books > Non-fiction > Essential programming'.

        It's rarely used in Oscar's codebase, but used to be stored as a
        CharField and is hence kept for backwards compatibility. It's also
        sufficiently useful to keep around.
        c             S   s   g | ]
}|j qS r9   )r)   ).0categoryr9   r9   r:   
<listcomp>t   s    z.AbstractCategory.full_name.<locals>.<listcomp>)get_ancestors_and_self_full_name_separatorjoin)r<   namesr9   r9   r:   rU   j   s    
zAbstractCategory.full_namec             C   s   dd | j  D }| jj|S )ab  
        Returns a string of this category's slug concatenated with the slugs
        of it's ancestors, e.g. 'books/non-fiction/essential-programming'.

        Oscar used to store this as in the 'slug' model field, but this field
        has been re-purposed to only store this category's slug and to not
        include it's ancestors' slugs.
        c             S   s   g | ]
}|j qS r9   )rC   )rV   rW   r9   r9   r:   rX      s    z.AbstractCategory.full_slug.<locals>.<listcomp>)rY   _slug_separatorr[   )r<   Zslugsr9   r9   r:   	full_slugw   s    
zAbstractCategory.full_slugc             C   s
   t | jS )zm
        Generates a slug for a category. This makes no attempt at generating
        a unique slug.
        )r   r)   )r<   r9   r9   r:   generate_slug   s    zAbstractCategory.generate_slugc                s"   | j s| j | _ t j|| dS )aB  
        Oscar traditionally auto-generated slugs from names. As that is
        often convenient, we still do so if a slug is not supplied through
        other means. If you want to control slug creation, just create
        instances with a slug already set, or expose a field on the
        appropriate forms.
        N)rC   r_   supersave)r<   argskwargs)	__class__r9   r:   ra      s    
zAbstractCategory.savec             C   s   t | j | g S )z
        Gets ancestors and includes itself. Use treebeard's get_ancestors
        if you don't want to include the category itself. It's a separate
        function as it's commonly used in templates.
        )listZget_ancestors)r<   r9   r9   r:   rY      s    z'AbstractCategory.get_ancestors_and_selfc             C   s   t | j | g S )z
        Gets descendants and includes itself. Use treebeard's get_descendants
        if you don't want to include the category itself. It's a separate
        function as it's commonly used in templates.
        )re   Zget_descendants)r<   r9   r9   r:   get_descendants_and_self   s    z)AbstractCategory.get_descendants_and_selfc             C   s   t  }d|| jf }|S )NzCATEGORY_URL_%s_%s)r   rJ   )r<   Zcurrent_locale	cache_keyr9   r9   r:   get_url_cache_key   s    z"AbstractCategory.get_url_cache_keyc             C   s<   | j  }tj|}|s8td| j| jdd}tj|| |S )a  
        Our URL scheme means we have to look up the category's ancestors. As
        that is a bit more expensive, we cache the generated URL. That is
        safe even for a stale cache, as the default implementation of
        ProductCategoryView does the lookup via primary key anyway. But if
        you change that logic, you'll have to reconsider the caching
        approach.
        zcatalogue:category)Zcategory_slugrJ   )rc   )rh   r   getr   r^   rJ   set)r<   rg   urlr9   r9   r:   get_absolute_url   s    	
z!AbstractCategory.get_absolute_urlc               @   s*   e Zd ZdZdZdgZedZedZdS )zAbstractCategory.MetaTr0   rK   Category
CategoriesN)	r1   r2   r3   r4   r5   r6   r7   r/   r8   r9   r9   r9   r:   r;      s
   r;   c             C   s   | j  dkS )Nr   )get_num_children)r<   r9   r9   r:   has_children   s    zAbstractCategory.has_childrenc             C   s   | j  j S )N)Zget_childrencount)r<   r9   r9   r:   ro      s    z!AbstractCategory.get_num_children)rJ   rK   rL   )r1   r2   r3   rA   ZCOMPARISON_FIELDSr   rB   r7   r)   	TextFielddescription
ImageFieldimager   rC   r]   rZ   r=   rH   rU   r^   r_   ra   rY   rf   rh   rl   r;   rp   ro   __classcell__r9   r9   )rd   r:   rI   R   s*   
rI   c               @   sR   e Zd ZdZejdejeddZejdejeddZ	G dd dZ
d	d
 ZdS )AbstractProductCategoryzU
    Joining model between products and categories. Exists to allow customising.
    zcatalogue.ProductProduct)	on_deleter/   zcatalogue.Categoryrm   c               @   s0   e Zd ZdZdZddgZdZedZedZ	dS )	zAbstractProductCategory.MetaTr0   productrW   zProduct categoryzProduct categoriesN)rz   rW   )
r1   r2   r3   r4   r5   r6   unique_togetherr7   r/   r8   r9   r9   r9   r:   r;      s   r;   c             C   s
   d| j  S )Nz"<productcategory for product '%s'>)rz   )r<   r9   r9   r:   r=      s    zAbstractProductCategory.__str__N)r1   r2   r3   rA   r   
ForeignKeyCASCADEr7   rz   rW   r;   r=   r9   r9   r9   r:   rw      s   rw   c            	       s  e Zd ZdZd~\ZZZeedfeedfeedffZe	j
edd	eed
ZeedddddeddZe	jddde	jdededdZe	j
edddddZe	jeddddZe	jedddZe	jddde	jedded d!Ze	jd"d#ed$ed%d&Ze	jd'ded(ed)d*Ze	jd+d,ded-ed.d/Ze	jed0ddd1Ze	jed2dd3Z e	jed4ddd5Z!e	jd6d7ed8d9Z"e	j#ed:ded;d<Z$e%j& Z'e( Z)G d=d> d>Z* fd?d@Z+dAdB Z,dCdD Z-dEdF Z.dGdH Z/dIdJ Z0dKdL Z1 fdMdNZ2e3dOdP Z4e3dQdR Z5e3dSdT Z6ddUdVZ7e3dWdX Z8e9dYdZ Z:e3d[d\ Z;e3d]d^ Z<e3d_d` Z=e3dadb Z>dcdd Z?edde?_@dedf ZAedgeA_@dhdi ZBdjdk ZCed8eC_@dldm ZDdndo ZEdpdq ZFdrds ZGdeG_Hdtdu ZIdvdw ZJdxdy ZKe9dzd{ ZLe3d|d} ZM  ZNS )AbstractProducta8  
    The base product object

    There's three kinds of products; they're distinguished by the structu{% include "partials/footer.html" %}re
    field.

    - A stand alone product. Regular product that lives by itself.
    - A child product. All child products have a parent product. They're a
      specific version of the parent.
    - A parent product. It essentially represents a set of products.

    An example could be a yoga course, which is a parent product. The different
    times/locations of the courses would be associated with the child products.
    
standaloneparentchildzStand-alone productzParent productzChild productzProduct structure
   )r'   choicesr,   UPC@   TzUniversal Product Code (UPC) is an identifier for a product which is not specific to a particular  supplier. Eg an ISBN for a book.)r'   r.   rS   r*   	help_textr<   childrenzOnly choose a parent product if you're creating a child product.  For example if this is a size 4 of a particular t-shirt.  Leave blank if this is a stand-alone product (i.e. there is only one version of this product).)r.   rS   ry   related_namer/   r   zProduct titleTitlerM   )r'   r.   r(   F)r'   r*   rO   )r.   zcatalogue.ProductClasszProduct typeZproductsz#Choose what type of product this is)rS   r.   ry   r/   r   r   zcatalogue.ProductAttributeProductAttributeValueZ
AttributeszfA product attribute is something that this product may have, such as a size, as specified by its class)throughr/   r   zcatalogue.OptionzProduct optionszOptions are values that can be associated with a item when it is added to a customer's basket.  This could be something like a personalised message to be printed on a T-shirt.)r.   r/   r   zcatalogue.ProductZProductRecommendationzRecommended productszFThese are products that are recommended to accompany the main product.)r   r.   r/   r   Rating)rS   editablezDate created)auto_now_addzDate updated)auto_nowrN   zcatalogue.CategoryProductCategoryrn   )r   r/   zIs discountable?zBThis flag indicates if this product can be used in an offer or not)r,   r   c               @   s*   e Zd ZdZdZdgZedZedZdS )zAbstractProduct.MetaTr0   z-date_createdrx   ProductsN)	r1   r2   r3   r4   r5   r6   r7   r/   r8   r9   r9   r9   r:   r;   R  s
   r;   c                s   t  j|| t| d| _d S )N)rz   )r`   __init__r"   attr)r<   rb   rc   )rd   r9   r:   r   Y  s    zAbstractProduct.__init__c             C   s0   | j r| j S | jr$d| j | jf S | j S d S )Nz%s (%s))titleattribute_summary	get_title)r<   r9   r9   r:   r=   ]  s
    zAbstractProduct.__str__c             C   s   t d| j| jddS )z1
        Return a product's absolute url
        zcatalogue:detail)Zproduct_slugrJ   )rc   )r   rC   id)r<   r9   r9   r:   rl   e  s    z AbstractProduct.get_absolute_urlc             C   s&   t | d| j   | js"| jj  dS )a   
        Validate a product. Those are the rules:

        +---------------+-------------+--------------+--------------+
        |               | stand alone | parent       | child        |
        +---------------+-------------+--------------+--------------+
        | title         | required    | required     | optional     |
        +---------------+-------------+--------------+--------------+
        | product class | required    | required     | must be None |
        +---------------+-------------+--------------+--------------+
        | parent        | forbidden   | forbidden    | required     |
        +---------------+-------------+--------------+--------------+
        | stockrecords  | 0 or more   | forbidden    | 0 or more    |
        +---------------+-------------+--------------+--------------+
        | categories    | 1 or more   | 1 or more    | forbidden    |
        +---------------+-------------+--------------+--------------+
        | attributes    | optional    | optional     | optional     |
        +---------------+-------------+--------------+--------------+
        | rec. products | optional    | optional     | unsupported  |
        +---------------+-------------+--------------+--------------+
        | options       | optional    | optional     | forbidden    |
        +---------------+-------------+--------------+--------------+

        Because the validation logic is quite complex, validation is delegated
        to the sub method appropriate for the product's structure.
        z	_clean_%sN)getattr	structure	is_parentr   Zvalidate_attributes)r<   r9   r9   r:   cleanl  s    zAbstractProduct.cleanc             C   s:   | j sttd| js$ttd| jr6ttddS )z1
        Validates a stand-alone product
        zYour product must have a title.z'Your product must have a product class.z&Only child products can have a parent.N)r   r
   r7   product_class	parent_id)r<   r9   r9   r:   _clean_standalone  s    z!AbstractProduct._clean_standalonec             C   s|   | j sttd| j r.| jj r.ttd| jr@ttd| jr\| jj r\ttd| jrx| j	j rxttddS )z+
        Validates a child product
        zA child product needs a parent.z6You can only assign child products to parent products.z+A child product can't have a product class.z/A child product can't have a category assigned.z#A child product can't have options.N)
r   r
   r7   r   r   r   rJ   rQ   r?   product_options)r<   r9   r9   r:   _clean_child  s    


zAbstractProduct._clean_childc             C   s   | j   | jrttddS )z-
        Validates a parent product.
        z)A parent product can't have stockrecords.N)r   has_stockrecordsr
   r7   )r<   r9   r9   r:   _clean_parent  s    zAbstractProduct._clean_parentc                s0   | j st| j | _ t j|| | jj  d S )N)rC   r   r   r`   ra   r   )r<   rb   rc   )rd   r9   r:   ra     s    zAbstractProduct.savec             C   s   | j | jkS )N)r   
STANDALONE)r<   r9   r9   r:   is_standalone  s    zAbstractProduct.is_standalonec             C   s   | j | jkS )N)r   PARENT)r<   r9   r9   r:   r     s    zAbstractProduct.is_parentc             C   s   | j | jkS )N)r   CHILD)r<   r9   r9   r:   is_child  s    zAbstractProduct.is_childc             C   s<   d}| j rtd}| jr td}|dk}|r4||fS |S dS )zT
        Helps decide if a the product can be turned into a parent product.
        Nz0The specified parent product is a child product.z>One can't add a child product to a product with stock records.)r   r7   r   )r<   Zgive_reasonreasonis_validr9   r9   r:   can_be_parent  s    zAbstractProduct.can_be_parentc             C   s$   | j  jj }t|p"t| jj S )z
        Returns a set of all valid options for this product.
        It's possible to have options product class-wide, and per product.
        )get_product_classrG   allrj   r   )r<   Zpclass_optionsr9   r9   r:   rG     s    zAbstractProduct.optionsc             C   sP   t | dd }t | dd }|d k	r8|d k	r8|dkp6|dkS | j jj pN| jj S )Nnum_product_class_optionsnum_product_optionsr   )r   r   rG   r?   r   )r<   r   r   r9   r9   r:   has_options  s
    zAbstractProduct.has_optionsc             C   s
   | j  jS )N)r   rE   )r<   r9   r9   r:   is_shipping_required  s    z$AbstractProduct.is_shipping_requiredc             C   s
   | j j S )z;
        Test if this product has any stockrecords
        )stockrecordsr?   )r<   r9   r9   r:   r     s    z AbstractProduct.has_stockrecordsc             C   s
   | j j S )N)r   rq   )r<   r9   r9   r:   num_stockrecords  s    z AbstractProduct.num_stockrecordsc             C   s"   | j j }dd |D }dj|S )zB
        Return a string of all of a product's attributes
        c             S   s   g | ]}|j  qS r9   )summary)rV   	attributer9   r9   r:   rX      s    z5AbstractProduct.attribute_summary.<locals>.<listcomp>z, )attribute_valuesr   r[   )r<   r>   pairsr9   r9   r:   r     s    
z!AbstractProduct.attribute_summaryc             C   s   | j }| r| jr| jj }|S )zT
        Return a product's title or it's parent's title if it has no title
        )r   r   r   )r<   r   r9   r9   r:   r     s    zAbstractProduct.get_titlec             C   s   | j r| jjS | jS dS )zW
        Return a product's item class. Child products inherit their parent's.
        N)r   r   r   )r<   r9   r9   r:   r     s    z!AbstractProduct.get_product_classzProduct classc             C   s   | j r| jjS | jS dS )z
        At the moment, is_discountable can't be set individually for child
        products; they inherit it from their parent.
        N)r   r   is_discountable)r<   r9   r9   r:   get_is_discountable  s    z#AbstractProduct.get_is_discountablec             C   s   | j r| jjS | jS dS )zY
        Return a product's categories or parent's if there is a parent product.
        N)r   r   rQ   )r<   r9   r9   r:   get_categories!  s    zAbstractProduct.get_categoriesc             C   s   t  S )z1
        Returns a missing image object.
        )MissingProductImage)r<   r9   r9   r:   get_missing_image-  s    z!AbstractProduct.get_missing_imagec             C   s(   | j r| jj  r| jjj S | jj S )N)r   imagesr?   r   r   )r<   r9   r9   r:   get_all_images5  s    zAbstractProduct.get_all_imagesc             C   s^   | j  }| jjjj}| s&|d dkr0|jd}y|d S  tk
rX   | j dddS X dS )z
        Returns the primary image for a product. Usually used when one can
        only display one product image, e.g. in a list of products.
        r   display_order T)originalcaptionZ
is_missingN)r   r   modelr;   r6   order_by
IndexErrorr   )r<   r   r6   r9   r9   r:   primary_image:  s    
zAbstractProduct.primary_imagec             C   s   | j  | _| j  dS )z*
        Recalculate rating field
        N)calculate_ratingratingra   )r<   r9   r9   r:   update_ratingS  s    
zAbstractProduct.update_ratingc             C   sZ   | j j| j jjdjtdtdd}|d p0d}|d p<d}d}|dkrVt|| }|S )	z(
        Calculate rating value
        )statusscorer   )sumrq   r   r   rq   N)reviewsfilterr   ZAPPROVED	aggregater   r   float)r<   resultreviews_sumreviews_countr   r9   r9   r:   r   [  s    z AbstractProduct.calculate_ratingc             C   s   |j r
dS | jj|dj S )NF)user)is_anonymousr   r   r?   )r<   r   r9   r9   r:   has_review_byj  s    zAbstractProduct.has_review_byc             C   s    |j stjr| j| S dS dS )ak  
        Determines whether a user may add a review on this product.

        Default implementation respects OSCAR_ALLOW_ANON_REVIEWS and only
        allows leaving one review per user and product.

        Override this if you want to alter the default behaviour; e.g. enforce
        that a user purchased the product to be allowed to leave a review.
        FN)is_authenticatedr   OSCAR_ALLOW_ANON_REVIEWSr   )r<   r   r9   r9   r:   is_review_permittedo  s    
z#AbstractProduct.is_review_permittedc             C   s   | j j j S )N)r   approvedrq   )r<   r9   r9   r:   num_approved_reviews~  s    z$AbstractProduct.num_approved_reviewsc             C   s   dd | j jdj D S )z(Keeping order by recommendation ranking.c             S   s   g | ]
}|j qS r9   )recommendation)rV   rr9   r9   r:   rX     s    z?AbstractProduct.sorted_recommended_products.<locals>.<listcomp>r   )primary_recommendationsselect_relatedr   )r<   r9   r9   r:   sorted_recommended_products  s    z+AbstractProduct.sorted_recommended_products)r   r   r   )F)Or1   r2   r3   rA   r   r   r   r7   ZSTRUCTURE_CHOICESr   rB   r   r   upcr|   r}   r   r   r   r   rC   rr   rs   PROTECTr   rF   r>   r   Zrecommended_products
FloatFieldr   DateTimeFielddate_createddate_updatedrQ   rD   r   r!   
as_managerobjectsr    Z	browsabler;   r   r=   rl   r   r   r   r   ra   rH   r   r   r   r   rG   r   r   r   r   r   r   r   short_descriptionr   r   r   r   r   r   r   alters_datar   r   r   r   r   rv   r9   r9   )rd   r:   r~      s   







	
	
	


r~   c               @   sd   e Zd ZdZejdejdeddZejdejeddZ	ej
edd	ed
dZG dd dZdS )AbstractProductRecommendationz5
    'Through' model for product recommendations
    zcatalogue.Productr   zPrimary product)ry   r   r/   zRecommended product)ry   r/   ZRankingr   zlDetermines order of the products. A product with a higher value will appear before one with a lower ranking.)r,   r   c               @   s0   e Zd ZdZdZddgZd	ZedZedZ	dS )
z"AbstractProductRecommendation.MetaTr0   primaryz-rankingr   zProduct recommendationzProduct recomendationsN)r   r   )
r1   r2   r3   r4   r5   r6   r{   r7   r/   r8   r9   r9   r9   r:   r;     s   r;   N)r1   r2   r3   rA   r   r|   r}   r7   r   r   PositiveSmallIntegerFieldZrankingr;   r9   r9   r9   r:   r     s   r   c               @   s  e Zd ZdZejddejddeddZej	eddd	Z
ejed
dededdegdZdZdZdZdZdZdZdZdZdZdZdZdZeedfeedfeedfeedfeedfeed feed!feed"feed#feed$feed%feed&ffZej	eed' d' d(ed)d*Zejd+ddejd,ed-ed.d/Zejed0d1d2ZG d3d4 d4Z e!d5d6 Z"e!d7d8 Z#e!d9d: Z$d;d< Z%d=d> Z&d?d@ Z'dAdB Z(dCdD Z)dEdF Z*dGdH Z+e+Z,dIdJ Z-dKdL Z.dMdN Z/dOdP Z0dQdR Z1dSdT Z2dUdV Z3d\dXdYZ4dZd[ Z5e5Z6dWS )]AbstractProductAttributezi
    Defines an attribute for a product class. (For example, number_of_pages for
    a 'book' class)
    zcatalogue.ProductClassTr>   zProduct type)r.   ry   r   rS   r/   r%   r&   )r'   Codez^[a-zA-Z_][0-9a-zA-Z_]*$zbCode can only contain the letters a-z, A-Z, digits, and underscores, and can't start with a digit.)regexmessage)r'   
validatorstextintegerbooleanr   Zrichtextr   r   optionZmulti_optionentityfileru   TextIntegerzTrue / FalseFloatz	Rich TextDateZDatetimeOptionzMulti OptionEntityr   rP   r      Type)r   r,   r'   r/   zcatalogue.AttributeOptionGroupZproduct_attributeszOption Groupz?Select an option group if using type "Option" or "Multi Option")r.   rS   ry   r   r/   r   RequiredF)r,   c               @   s*   e Zd ZdZdZdgZedZedZdS )zAbstractProductAttribute.MetaTr0   codezProduct attributezProduct attributesN)	r1   r2   r3   r4   r5   r6   r7   r/   r8   r9   r9   r9   r:   r;     s
   r;   c             C   s   | j | jkS )N)typeOPTION)r<   r9   r9   r:   	is_option  s    z"AbstractProductAttribute.is_optionc             C   s   | j | jkS )N)r  MULTI_OPTION)r<   r9   r9   r:   is_multi_option  s    z(AbstractProductAttribute.is_multi_optionc             C   s   | j | j| jgkS )N)r  FILEIMAGE)r<   r9   r9   r:   is_file  s    z AbstractProductAttribute.is_filec             C   s   | j S )N)r)   )r<   r9   r9   r:   r=     s    z AbstractProductAttribute.__str__c             C   s0   |d krd S |dkr|j   n||_|j  d S )NF)deletevaluera   )r<   	value_objr  r9   r9   r:   
_save_file  s    
z#AbstractProductAttribute._save_filec             C   sf   |d kr|j   d S y|j }W n  ttfk
r@   t|}Y nX |dkrT|j   n||_|j  d S )Nr   )r
  rq   AttributeError	TypeErrorlenr  ra   )r<   r  r  rq   r9   r9   r:   _save_multi_option	  s    
z+AbstractProductAttribute._save_multi_optionc             C   s8   |d ks|dkr|j   d S ||jkr4||_|j  d S )Nr   )r
  r  ra   )r<   r  r  r9   r9   r:   _save_value  s    
z$AbstractProductAttribute._save_valuec             C   s   t dd}y|jj| d}W nL |jk
rh   | jo:|dk}|d ksP|dksP|rTd S |jj|| d}Y nX | jr~| j|| n | jr| j	|| n| j
|| d S )Nr0   r   )r   Fr   )rz   r   )r   r   ri   DoesNotExistr	  r   creater  r  r  r  )r<   rz   r  r   r  delete_filer9   r9   r:   
save_value   s    
z#AbstractProductAttribute.save_valuec             C   s   t | d| j }|| d S )Nz_validate_%s)r   r  )r<   r  	validatorr9   r9   r:   validate_value4  s    z'AbstractProductAttribute.validate_valuec             C   s   t |tsttdd S )NzMust be str)
isinstancestrr
   r7   )r<   r  r9   r9   r:   _validate_text:  s    
z'AbstractProductAttribute._validate_textc             C   s2   yt | W n  tk
r,   ttdY nX d S )NzMust be a float)r   
ValueErrorr
   r7   )r<   r  r9   r9   r:   _validate_float?  s    z(AbstractProductAttribute._validate_floatc             C   s2   yt | W n  tk
r,   ttdY nX d S )NzMust be an integer)intr  r
   r7   )r<   r  r9   r9   r:   _validate_integerE  s    z*AbstractProductAttribute._validate_integerc             C   s$   t |tpt |ts ttdd S )NzMust be a date or datetime)r  r   r   r
   r7   )r<   r  r9   r9   r:   _validate_dateK  s    z'AbstractProductAttribute._validate_datec             C   s   t |tsttdd S )NzMust be a datetime)r  r   r
   r7   )r<   r  r9   r9   r:   _validate_datetimeO  s    
z+AbstractProductAttribute._validate_datetimec             C   s   t |tksttdd S )NzMust be a boolean)r  boolr
   r7   )r<   r  r9   r9   r:   _validate_booleanS  s    z*AbstractProductAttribute._validate_booleanc             C   s   t |tjsttdd S )NzMust be a model instance)r  r   Modelr
   r7   )r<   r  r9   r9   r:   _validate_entityW  s    z)AbstractProductAttribute._validate_entityc             C   s`   yt |}W n  tk
r,   ttdY nX | jjjddd}x|D ]}| j||d qFW d S )Nz*Must be a list or AttributeOption querysetr   T)flat)valid_values)iterr  r
   r7   option_grouprG   values_list_validate_option)r<   r  valuesr'  r9   r9   r:   _validate_multi_option[  s    

z/AbstractProductAttribute._validate_multi_optionNc             C   sl   t |tddsttd|js.ttd|d krH| jjjddd}|j|krhttd|| d	 d S )
Nr0   AttributeOptionz0Must be an AttributeOption model object instancez&AttributeOption has not been saved yetr   T)r&  z+%(enum)s is not a valid choice for %(attr)s)enumr   )	r  r   r
   r7   rJ   r)  rG   r*  r   )r<   r  r'  r9   r9   r:   r+  h  s    


z)AbstractProductAttribute._validate_optionc             C   s    |rt |t rttdd S )NzMust be a file field)r  r   r
   r7   )r<   r  r9   r9   r:   _validate_filev  s    z'AbstractProductAttribute._validate_file)N)7r1   r2   r3   rA   r   r|   r}   r7   r   rB   r)   r   r   r   r  TEXTINTEGERBOOLEANFLOATZRICHTEXTDATEDATETIMEr  r  ZENTITYr  r  TYPE_CHOICESr  r)  rD   requiredr;   rH   r  r  r	  r=   r  r  r  r  r  r  Z_validate_richtextr  r  r   r!  r#  r%  r-  r+  r0  Z_validate_imager9   r9   r9   r:   r     s   












r   c               @   s  e Zd ZdZejdejeddZejdejdeddZ	ej
ed	d
d
dZejedd
d
dZejedd
dZejedd
d
dZej
edd
d
dZejedd
d
dZejedd
d
dZejdd
deddZejdd
d
ejeddZejejdd
d
dZejejdd
d
dZe ddZ!eje"d
dejd
dZ#ej$d
d
ddZ%d d! Z&d"d# Z'e(e&e'Z)G d$d% d%Z*d&d' Z+d(d) Z,e(d*d+ Z-e(d,d- Z.e(d.d/ Z/e(d0d1 Z0e(d2d3 Z1e(d4d5 Z2d6S )7AbstractProductAttributeValuez
    The "through" model for the m2m relationship between catalogue.Product and
    catalogue.ProductAttribute.  This specifies the value of the attribute for
    a particular product

    For example: number_of_pages = 295
    zcatalogue.ProductAttribute	Attribute)ry   r/   zcatalogue.Productr   rx   )ry   r   r/   r   T)r.   rS   r   Boolean)r.   r   ZRichtextr   DateTimezcatalogue.AttributeOptionZmulti_valued_attribute_valueszValue multi option)r.   r   r/   zValue option)r.   rS   ry   r/   rM   )rR   r'   r.   rS   entity_content_typeentity_object_idF)r.   r   ry   rS   )rS   r.   r   c             C   s(   t | d| jj }t|dr$|j }|S )Nzvalue_%sr   )r   r   r  hasattrr   )r<   r  r9   r9   r:   
_get_value  s    
z(AbstractProductAttributeValue._get_valuec             C   s^   d| j j }| j jr2t|tr2| j jjj|d}n| j jrNt	| |j
| d S t| || d S )Nzvalue_%s)r   )r   r  r  r  r  r)  rG   ri   r  r   rj   setattr)r<   	new_value	attr_namer9   r9   r:   
_set_value  s    

z(AbstractProductAttributeValue._set_valuec               @   s(   e Zd ZdZdZdZedZedZdS )	z"AbstractProductAttributeValue.MetaTr0   r   rz   zProduct attribute valuezProduct attribute valuesN)r   rz   )	r1   r2   r3   r4   r5   r{   r7   r/   r8   r9   r9   r9   r:   r;     s
   r;   c             C   s   | j  S )N)r   )r<   r9   r9   r:   r=     s    z%AbstractProductAttributeValue.__str__c             C   s   d| j j| jf S )z{
        Gets a string representation of both the attribute and it's value,
        used e.g in product summaries.
        z%s: %s)r   r)   value_as_text)r<   r9   r9   r:   r     s    z%AbstractProductAttributeValue.summaryc             C   s   d| j j }t| || jS )z
        Returns a string representation of the attribute's value. To customise
        e.g. image attribute values, declare a _image_as_text property and
        return something appropriate.
        z_%s_as_text)r   r  r   r  )r<   property_namer9   r9   r:   rE    s    z+AbstractProductAttributeValue.value_as_textc             C   s   dj dd | jj D S )Nz, c             s   s   | ]}t |V  qd S )N)r  )rV   r   r9   r9   r:   	<genexpr>  s    zFAbstractProductAttributeValue._multi_option_as_text.<locals>.<genexpr>)r[   value_multi_optionr   )r<   r9   r9   r:   _multi_option_as_text  s    z3AbstractProductAttributeValue._multi_option_as_textc             C   s
   t | jS )N)r   r  )r<   r9   r9   r:   _richtext_as_text  s    z/AbstractProductAttributeValue._richtext_as_textc             C   s
   t | jS )z
        Returns the unicode representation of the related model. You likely
        want to customise this (and maybe _entity_as_html) if you use entities.
        )r  r  )r<   r9   r9   r:   _entity_as_text  s    z-AbstractProductAttributeValue._entity_as_textc             C   s   d| j j }t| || jS )z
        Returns a HTML representation of the attribute's value. To customise
        e.g. image attribute values, declare a _image_as_html property and
        return e.g. an <img> tag.  Defaults to the _as_text representation.
        z_%s_as_html)r   r  r   rE  )r<   rF  r9   r9   r:   value_as_html  s    z+AbstractProductAttributeValue.value_as_htmlc             C   s
   t | jS )N)r   r  )r<   r9   r9   r:   _richtext_as_html  s    z/AbstractProductAttributeValue._richtext_as_htmlN)3r1   r2   r3   rA   r   r|   r}   r7   r   rz   rr   Z
value_textIntegerFieldZvalue_integerNullBooleanFieldZvalue_booleanr   Zvalue_floatZvalue_richtext	DateFieldZ
value_dater   Zvalue_datetimerF   rH  Zvalue_option	FileFieldr   OSCAR_IMAGE_FOLDERZ
value_filert   Zvalue_imager   Zvalue_entityr   r=  PositiveIntegerFieldr>  r@  rD  rH   r  r;   r=   r   rE  rI  rJ  rK  rL  rM  r9   r9   r9   r:   r9  |  sn   




r9  c               @   sD   e Zd ZdZejedddZdd ZG dd dZ	e
d	d
 ZdS )AbstractAttributeOptionGroupzv
    Defines a group of options that collectively may be used as an
    attribute type

    For example, Language
    r%   r&   )r'   c             C   s   | j S )N)r)   )r<   r9   r9   r:   r=   
  s    z$AbstractAttributeOptionGroup.__str__c               @   s$   e Zd ZdZdZedZedZdS )z!AbstractAttributeOptionGroup.MetaTr0   zAttribute option groupzAttribute option groupsN)r1   r2   r3   r4   r5   r7   r/   r8   r9   r9   r9   r:   r;     s   r;   c             C   s   dd | j j D }dj|S )Nc             S   s   g | ]
}|j qS r9   )r   )rV   or9   r9   r:   rX     s    z?AbstractAttributeOptionGroup.option_summary.<locals>.<listcomp>z, )rG   r   r[   )r<   rG   r9   r9   r:   option_summary  s    z+AbstractAttributeOptionGroup.option_summaryN)r1   r2   r3   rA   r   rB   r7   r)   r=   r;   rH   rV  r9   r9   r9   r:   rT    s
   rT  c               @   sP   e Zd ZdZejdejdeddZej	edddZ
d	d
 ZG dd dZdS )AbstractAttributeOptionz
    Provides an option within an option group for an attribute type
    Examples: In a Language group, English, Greek, French
    zcatalogue.AttributeOptionGrouprG   Group)ry   r   r/   r   rM   )r'   c             C   s   | j S )N)r   )r<   r9   r9   r:   r=   %  s    zAbstractAttributeOption.__str__c               @   s(   e Zd ZdZdZdZedZedZdS )	zAbstractAttributeOption.MetaTr0   groupr   zAttribute optionzAttribute optionsN)rY  r   )	r1   r2   r3   r4   r5   r{   r7   r/   r8   r9   r9   r9   r:   r;   (  s
   r;   N)r1   r2   r3   rA   r   r|   r}   r7   rY  rB   r   r=   r;   r9   r9   r9   r:   rW    s   rW  c               @   s   e Zd ZdZejedddZeedddddZ	d\Z
Ze
edfeedffZejedde
edZG dd dZdd Zedd ZdS )AbstractOptiona  
    An option that can be selected for a particular item when the product
    is added to the basket.

    For example,  a list ID for an SMS message send, or a personalised message
    to print on a T-shirt.

    This is not the same as an 'attribute' as options do not have a fixed value
    for a particular item.  Instead, option need to be specified by a customer
    when they add the item to their basket.
    r%   r&   )r'   r   Tr)   )r'   r*   r+   r   Optionalz4Required - a value for this option must be specifiedz1Optional - a value for this option can be omittedStatus)r'   r,   r   c               @   s$   e Zd ZdZdZedZedZdS )zAbstractOption.MetaTr0   r   r-   N)r1   r2   r3   r4   r5   r7   r/   r8   r9   r9   r9   r:   r;   H  s   r;   c             C   s   | j S )N)r)   )r<   r9   r9   r:   r=   N  s    zAbstractOption.__str__c             C   s   | j | jkS )N)r  REQUIRED)r<   r9   r9   r:   is_requiredQ  s    zAbstractOption.is_requiredN)r   r[  )r1   r2   r3   rA   r   rB   r7   r)   r   r  r]  OPTIONALr7  r  r;   r=   rH   r^  r9   r9   r9   r:   rZ  0  s   
rZ  c               @   s"   e Zd ZdZdddZdd ZdS )r   a  
    Mimics a Django file field by having a name property.

    sorl-thumbnail requires all it's images to be in MEDIA_ROOT. This class
    tries symlinking the default "missing image" image in STATIC_ROOT
    into MEDIA_ROOT for convenience, as that is necessary every time an Oscar
    project is setup. This avoids the less helpful NotFound IOError that would
    be raised when sorl-thumbnail tries to access it.
    Nc             C   sD   |r|nt j| _tjjt j| j}t jr@tjj| r@| j| d S )N)	r   OSCAR_MISSING_IMAGE_URLr)   osrK   r[   
MEDIA_ROOTr?   symlink_missing_image)r<   r)   media_file_pathr9   r9   r:   r   b  s    zMissingProductImage.__init__c             C   s   t d| j }|d k	ry2tjj|}tjj|s:tj| tj|| W n& tk
rn   t	d|t
jf Y nX tjd|t
jf  d S )Nzoscar/img/%szPlease copy/symlink the 'missing image' image at %s into your MEDIA_ROOT at %s. This exception was raised because Oscar was unable to symlink it for you.zDSymlinked the 'missing image' image at %s into your MEDIA_ROOT at %s)r   r)   ra  rK   dirnamer?   makedirssymlinkOSErrorr	   r   rb  logginginfo)r<   rd  Zstatic_file_pathZmedia_file_dirr9   r9   r:   rc  i  s     
z)MissingProductImage.symlink_missing_image)N)r1   r2   r3   rA   r   rc  r9   r9   r9   r:   r   V  s   

r   c                   s   e Zd ZdZejdejdeddZej	ede
jddZejed	d
ddZejeddeddZejedddZG dd dZdd Zdd Z fddZ  ZS )AbstractProductImagez
    An image of a product
    zcatalogue.Productr   rx   )ry   r   r/   ZOriginalrM   )rR   r'   ZCaption   T)r'   r.   zDisplay orderr   zMAn image with a display order of zero will be the primary image for a product)r,   r   zDate created)r   c               @   s*   e Zd ZdZdZdgZedZedZdS )zAbstractProductImage.MetaTr0   r   zProduct imagezProduct imagesN)	r1   r2   r3   r4   r5   r6   r7   r/   r8   r9   r9   r9   r:   r;     s
   r;   c             C   s
   d| j  S )NzImage of '%s')rz   )r<   r9   r9   r:   r=     s    zAbstractProductImage.__str__c             C   s
   | j dkS )z9
        Return bool if image display order is 0
        r   )r   )r<   r9   r9   r:   
is_primary  s    zAbstractProductImage.is_primaryc                s>   t  j|| x*t| jjj D ]\}}||_|j  q W dS )zh
        Always keep the display_order as consecutive integers. This avoids
        issue #855.
        N)r`   r
  	enumeraterz   r   r   r   ra   )r<   rb   rc   idxru   )rd   r9   r:   r
    s    zAbstractProductImage.delete)r1   r2   r3   rA   r   r|   r}   r7   rz   rt   r   rR  r   rB   r   rS  r   r   r   r;   r=   rm  r
  rv   r9   r9   )rd   r:   rk    s"   	rk  )*)Jri  ra  r   r   django.confr   Z"django.contrib.contenttypes.fieldsr   "django.contrib.contenttypes.modelsr   "django.contrib.staticfiles.findersr   django.core.cacher   django.core.exceptionsr	   r
   django.core.files.baser   Zdjango.core.validatorsr   	django.dbr   django.db.modelsr   r   django.urlsr   django.utils.functionalr   django.utils.htmlr   django.utils.safestringr   django.utils.translationr   r7   r   r   Ztreebeard.mp_treer   oscar.core.loadingr   r   oscar.core.utilsr   Zoscar.core.validatorsr   oscar.models.fieldsr   r   Zoscar.models.fields.slugfieldr   django.contrib.auth.modelsr   r    r!   r"   r#   r$  r$   rI   rw   r~   r   r   r9  rT  rW  rZ  objectr   rk  Zoscar.apps.customer.modelsr9   r9   r9   r:   <module>   s`   


-{   & Y &+1