3

\ܠ                 @   s  d dl Z d dl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 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( ej)d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+Z/G dd dej+Z0G d d! d!ej+Z1G d"d# d#ej+Z2G d$d% d%ej+Z3G d&d' d'ej+Z4G d(d) d)ej+Z5G d*d+ d+ej+Z6G d,d- d-ej+Z7G d.d/ d/ej+Z8G d0d1 d1ej+Z9dS )2    N)OrderedDict)Decimal)settings)ImproperlyConfigured)BadSignatureSigner)models)Sum)timezone)constant_time_compare)now)gettext_lazy)pgettext_lazy)order_line_status_changedorder_status_changed)AUTH_USER_MODEL)	get_model)get_default_currency)AutoSlugField   )
exceptionszoscar.orderc                   s  e Zd ZdZejedddddZejdeddej	dZ
ejd	ed
ddej	dZejedddedej	dZejdddedej	dZejedde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dZejedddddZejdddedej	dZejedddd Zejddd!d"Zejed#d$dd Zejed%dd&Zejdd'Zeed(i Z eed)i Z!e"d*d+ Z#d,d- Z$d.d/ Z%de%_&d0d1 Z'e(d2d3 Z)e(d4d5 Z*e(d6d7 Z+e(d8d9 Z,e(d:d; Z-e(d<d= Z.e(d>d? Z/e(d@dA Z0e(dBdC Z1e(dDdE Z2e(dFdG Z3e(dHdI Z4e(dJdK Z5e(dLdM Z6e(dNdO Z7e(dPdQ Z8dRdS Z9G dTdU dUZ:dVdW Z;dXdY Z<dZd[ Z=d\d] Z>e(d^d_ Z?e(d`da Z@e(dbdc ZAe(ddde ZBdfdg ZC fdhdiZD  ZES )jAbstractOrderz
    The main order model
    zOrder number   T)
max_lengthdb_indexuniquez
sites.SiteSite)verbose_namenull	on_deletezbasket.BasketBasket)r   r   blankr   ordersUser)related_namer   r!   r   r   zorder.BillingAddresszBilling Address)r   r!   r   r   ZCurrency   )r   defaultzOrder total (inc. tax)   )decimal_places
max_digitszOrder total (excl. tax)zShipping charge (inc. tax)r   )r(   r)   r&   zShipping charge (excl. tax)zorder.ShippingAddresszShipping AddresszShipping method)r   r!    )r!   r   r&   Statusd   zGuest email address)r!   )r   OSCAR_ORDER_STATUS_PIPELINEOSCAR_ORDER_STATUS_CASCADEc             C   s   t | jj S )z;
        Return all possible statuses for an order
        )listpipelinekeys)cls r3   ;/var/www/html/oscar2019/oscar/apps/order/abstract_models.pyall_statusesj   s    zAbstractOrder.all_statusesc             C   s   | j j| jf S )zJ
        Return all possible statuses that this order can move to
        )r0   getstatus)selfr3   r3   r4   available_statusesq   s    z AbstractOrder.available_statusesc             C   s   || j krdS | j }|| j kr>tjtd|| j| j d || _ || jkrxx(| jj D ]}| j| j  |_ |j	  qZW | j	  t
j| | ||d | j|| dS )z
        Set a new status for this order.

        If the requested status is not valid, then ``InvalidOrderStatus`` is
        raised.
        NzZ'%(new_status)s' is not a valid status for order %(number)s (current status: '%(status)s'))
new_statusnumberr7   )senderorder
old_statusr:   )r7   r9   r   ZInvalidOrderStatus_r;   cascadelinesallsaver   send_create_order_status_change)r8   r:   r>   liner3   r3   r4   
set_statusw   s(    

zAbstractOrder.set_statusc             C   s   | j j||d d S )N)r>   r:   )status_changescreate)r8   r>   r:   r3   r3   r4   rE      s    z)AbstractOrder._create_order_status_changec             C   s   | j d kot| jS )N)userboolguest_email)r8   r3   r3   r4   is_anonymous   s    zAbstractOrder.is_anonymousc             C   s*   t d}x| jj D ]}||j7 }qW |S )zT
        Return basket total including tax but before discounts are applied
        z0.00)DrA   rB   $line_price_before_discounts_incl_tax)r8   totalrF   r3   r3   r4   &basket_total_before_discounts_incl_tax   s    z4AbstractOrder.basket_total_before_discounts_incl_taxc             C   s*   t d}x| jj D ]}||j7 }qW |S )zT
        Return basket total excluding tax but before discounts are applied
        z0.00)rN   rA   rB   $line_price_before_discounts_excl_tax)r8   rP   rF   r3   r3   r4   &basket_total_before_discounts_excl_tax   s    z4AbstractOrder.basket_total_before_discounts_excl_taxc             C   s   | j | j S )z3
        Return basket total including tax
        )total_incl_taxshipping_incl_tax)r8   r3   r3   r4   basket_total_incl_tax   s    z#AbstractOrder.basket_total_incl_taxc             C   s   | j | j S )z3
        Return basket total excluding tax
        )total_excl_taxshipping_excl_tax)r8   r3   r3   r4   basket_total_excl_tax   s    z#AbstractOrder.basket_total_excl_taxc             C   s   | j | j S )N)rQ   rU   )r8   r3   r3   r4   total_before_discounts_incl_tax   s    z-AbstractOrder.total_before_discounts_incl_taxc             C   s   | j | j S )N)rS   rX   )r8   r3   r3   r4   total_before_discounts_excl_tax   s    z-AbstractOrder.total_before_discounts_excl_taxc             C   s*   t d}x| jj D ]}||j7 }qW |S )z<
        The amount of discount this order received
        z0.00)rN   rA   rB   discount_incl_tax)r8   discountrF   r3   r3   r4   total_discount_incl_tax   s    z%AbstractOrder.total_discount_incl_taxc             C   s*   t d}x| jj D ]}||j7 }qW |S )Nz0.00)rN   rA   rB   discount_excl_tax)r8   r]   rF   r3   r3   r4   total_discount_excl_tax   s    z%AbstractOrder.total_discount_excl_taxc             C   s   | j | j S )N)rT   rW   )r8   r3   r3   r4   	total_tax   s    zAbstractOrder.total_taxc             C   s
   | j j S )N)rA   count)r8   r3   r3   r4   	num_lines   s    zAbstractOrder.num_linesc             C   s&   d}x| j j D ]}||j7 }qW |S )z<
        Returns the number of items in this order.
        r   )rA   rB   quantity)r8   	num_itemsrF   r3   r3   r4   re      s    zAbstractOrder.num_itemsc             C   s   | j | j S )N)rU   rX   )r8   r3   r3   r4   shipping_tax   s    zAbstractOrder.shipping_taxc             C   s   | j jddj }t|sdS t }x<|D ]4}|jj}||krFg ||< || jt|j	j  q*W t
d}x"|j D ]\}}| j|rt|S qtW |S )z7Return the last complete shipping event for this order.z-date_createdz-pkr*   zIn progress)shipping_eventsorder_byrB   lenr   
event_typenameextendr/   line_quantitiesr?   items_is_event_complete)r8   events	event_mapevent
event_namer7   Zevent_line_quantitiesr3   r3   r4   shipping_status   s    

zAbstractOrder.shipping_statusc             C   s   t | jdkS )Nr   )ri   shipping_discounts)r8   r3   r3   r4   has_shipping_discounts  s    z$AbstractOrder.has_shipping_discountsc             C   s,   t d}x| jD ]}||j7 }qW | j| S )Nz0.00)rN   ru   amountrU   )r8   rP   r]   r3   r3   r4   "shipping_before_discounts_incl_tax  s    z0AbstractOrder.shipping_before_discounts_incl_taxc             C   sf   i }x0|D ](}|j }|j|d ||  |j7  < q
W x*| jj D ]}|j|jd|jkrBdS qBW dS )Nr   FT)line_id
setdefaultrd   rA   rB   r6   pk)r8   Zevent_quantitiesrq   event_quantityry   rF   r3   r3   r4   ro   !  s    
z AbstractOrder._is_event_completec               @   s*   e Zd ZdZdZdgZedZedZdS )zAbstractOrder.MetaTr=   z-date_placedOrderOrdersN)	__name__
__module____qualname__abstract	app_labelorderingr?   r   verbose_name_pluralr3   r3   r3   r4   Meta.  s
   r   c             C   s   d| j f S )Nz#%s)r;   )r8   r3   r3   r4   __str__5  s    zAbstractOrder.__str__c             C   s   t dd}|j| jS )Nzoscar.apps.order.Order)salt)r   signr;   )r8   signerr3   r3   r4   verification_hash8  s    
zAbstractOrder.verification_hashc             C   s`   t tdd}|dkrdS |tjkr*tdtjd d| j|f }tj|j	dj
 }t||S )a  
        Backward compatible check for md5 hashes that were generated in
        Oscar 1.5 and lower.

        This must explicitly be enabled by setting OSCAR_DEPRECATED_ORDER_VERIFY_KEY,
        which must not be equal to SECRET_KEY - i.e., the project must
        have changed its SECRET_KEY since this change was applied.

        TODO: deprecate this method in Oscar 2.0, and remove it in Oscar 2.1.
        Z!OSCAR_DEPRECATED_ORDER_VERIFY_KEYNFz?OSCAR_DEPRECATED_ORDER_VERIFY_KEY cannot be equal to SECRET_KEYz;Using insecure md5 hashing for order URL hash verification.z%s%sutf8)getattrr   
SECRET_KEYr   loggerwarningr;   hashlibmd5encode	hexdigestr   )r8   hash_to_checkZold_verification_keyZstring_to_hashZ
order_hashr3   r3   r4   "check_deprecated_verification_hash<  s    

z0AbstractOrder.check_deprecated_verification_hashc             C   sH   | j |rdS tdd}y|j|}W n tk
r:   dS X t|| jS )z
        Checks the received verification hash against this order number.
        Returns False if the verification failed, True otherwise.
        Tzoscar.apps.order.Order)r   F)r   r   unsignr   r   r;   )r8   r   r   Zsigned_numberr3   r3   r4   check_verification_hashT  s    

z%AbstractOrder.check_verification_hashc             C   s   | j s| jS | j jS )N)rJ   rL   email)r8   r3   r3   r4   r   d  s    zAbstractOrder.emailc             C   s   | j jtjdS )N)category)	discountsfilterAbstractOrderDiscountBASKET)r8   r3   r3   r4   basket_discountsj  s    zAbstractOrder.basket_discountsc             C   s   | j jtjdS )N)r   )r   r   r   SHIPPING)r8   r3   r3   r4   ru   q  s    z AbstractOrder.shipping_discountsc             C   s   | j jtjdS )N)r   )r   r   r   DEFERRED)r8   r3   r3   r4   post_order_actionsv  s    z AbstractOrder.post_order_actionsc             C   s   | j d krt | _ d S )N)date_placedr   )r8   r3   r3   r4   set_date_placed_default{  s    
z%AbstractOrder.set_date_placed_defaultc                s   | j   t j|| d S )N)r   superrC   )r8   argskwargs)	__class__r3   r4   rC     s    zAbstractOrder.save)Fr   r   r   __doc__r   	CharFieldr?   r;   
ForeignKeySET_NULLsitebasketr   rJ   Zbilling_addressr   currencyDecimalFieldrT   rW   rU   rX   shipping_addressshipping_methodshipping_coder7   
EmailFieldrL   DateTimeFieldr   r   r   r0   r@   classmethodr5   r9   rG   alters_datarE   propertyrM   rQ   rS   rV   rY   rZ   r[   r^   r`   ra   rc   re   rf   rt   rv   rx   ro   r   r   r   r   r   r   r   ru   r   r   rC   __classcell__r3   r3   )r   r4   r      s   





#



	r   c               @   s   e Zd ZdZejdejdeddZeje	ejdeddZ
d\ZZZZejeddddZejedZejedddZejedddZdZG dd dZdd Zdd ZdS )AbstractOrderNotez
    A note against an order.

    This are often used for audit purposes too.  IE, whenever an admin
    makes a change to an order, we create a note to record what happened.
    zorder.Ordernotesr}   )r   r$   r   Tr#   )r   r   r   InfoWarningErrorSystemz	Note Typer   )r   r!   MessagezDate Created)auto_now_addzDate Updated)auto_nowi,  c               @   s$   e Zd ZdZdZedZedZdS )zAbstractOrderNote.MetaTr=   z
Order NotezOrder NotesN)r   r   r   r   r   r?   r   r   r3   r3   r3   r4   r     s   r   c             C   s   d| j dd | jf S )Nz	'%s' (%s)r   2   )messagerJ   )r8   r3   r3   r4   r     s    zAbstractOrderNote.__str__c             C   s*   | j | jkrdS tj | j }|j| jk S )NF)	note_typeSYSTEMr
   r   date_updatedsecondseditable_lifetime)r8   deltar3   r3   r4   is_editable  s    zAbstractOrderNote.is_editableN)r   r   r   r   )r   r   r   r   r   r   CASCADEr?   r=   r   rJ   INFOWARNINGERRORr   r   r   	TextFieldr   r   date_createdr   r   r   r   r   r3   r3   r3   r4   r     s(   r   c               @   st   e Z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G dd dZdd ZdS )AbstractOrderStatusChangezorder.OrderrH   zOrder Status Changes)r   r$   r   z
Old Statusr,   T)r   r!   z
New StatuszDate Created)r   c               @   s*   e Zd ZdZdZedZedZdgZdS )zAbstractOrderStatusChange.MetaTr=   zOrder Status ChangezOrder Status Changesz-date_createdN)	r   r   r   r   r   r?   r   r   r   r3   r3   r3   r4   r     s
   r   c             C   s   t dj| j| j| jdS )Nz<{order} has changed status from {old_status} to {new_status})r=   r>   r:   )r?   formatr=   r>   r:   )r8   r3   r3   r4   r     s    z!AbstractOrderStatusChange.__str__N)r   r   r   r   r   r   r?   r=   r   r>   r:   r   r   r   r   r3   r3   r3   r4   r     s   r   c               @   sf   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
dZG dd dZdd ZdS )AbstractCommunicationEventzw
    An order-level event involving a communication to the customer, such
    as an confirmation email being sent.
    zorder.OrderZcommunication_eventsr}   )r   r$   r   zcustomer.CommunicationEventTypez
Event Type)r   r   DateT)r   c               @   s*   e Zd ZdZdZedZedZdgZdS )zAbstractCommunicationEvent.MetaTr=   zCommunication EventzCommunication Eventsz-date_createdN)	r   r   r   r   r   r?   r   r   r   r3   r3   r3   r4   r     s
   r   c             C   s   t d| jj| jjd S )Nz&'%(type)s' event for order #%(number)s)typer;   )r?   rj   rk   r=   r;   )r8   r3   r3   r4   r     s    z"AbstractCommunicationEvent.__str__N)r   r   r   r   r   r   r   r?   r=   rj   r   r   r   r   r3   r3   r3   r4   r     s   r   c               @   s  e Zd ZdZejdejdeddZejddddej	ed	d
Z
ejeddddZejedddZejedddeddZejedddZejdej	ddeddZejdej	ddeddZejeddddZejed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ed)d#d$ddd*Zejed+d#d$ddd*Zejed,d#d$ddd*Zejed-d#d$ddd*Z ejed.dddZ!ej"ed/ddd0Z#e$e%d1i Z&G d2d3 d3Z'd4d5 Z(e)d6d7 Z*d8d9 Z+d:d; Z,de,_-e.d<d= Z/e.d>d? Z0e.d@dA Z1e.dBdC Z2e.dDdE Z3e.dFdG Z4dHdI Z5dJdK Z6d[dMdNZ7dOdP Z8e.dQdR Z9dSdT Z:dUdV Z;e.dWdX Z<dYdZ Z=dLS )\AbstractLinez
    An order line
    zorder.OrderrA   r}   )r   r$   r   zpartner.PartnerZorder_linesTPartner)r$   r!   r   r   r   zPartner namer   )r   r!   zPartner SKU)r   zPartner referencezAThis is the item number that the partner uses within their system)r   r!   	help_textzPartner Notes)r!   zpartner.StockRecordzStock record)r   r!   r   r   zcatalogue.ProductZProductzProduct titleZTitle   ZUPC)r   r!   r   Quantityr   )r&   zPrice (inc. tax)r'   r%   )r(   r)   zPrice (excl. tax)z!Price before discounts (inc. tax)z"Price before discounts (excl. tax)zUnit Cost Price)r(   r)   r!   r   zUnit Price (inc. tax)zUnit Price (excl. tax)zUnit Retail Pricer+   zEstimated Dispatch Date)r!   r   ZOSCAR_LINE_STATUS_PIPELINEc               @   s*   e Zd ZdZdZdgZedZedZdS )zAbstractLine.MetaTr=   r{   z
Order LinezOrder LinesN)	r   r   r   r   r   r   r?   r   r   r3   r3   r3   r4   r   V  s
   r   c             C   s,   | j r| j j}ntd}td|| jd S )Nz<missing product>z&Product '%(name)s', quantity '%(qty)s')rk   qty)producttitler?   rd   )r8   r   r3   r3   r4   r   ^  s
    
zAbstractLine.__str__c             C   s   t | jj S )z@
        Return all possible statuses for an order line
        )r/   r0   r1   )r2   r3   r3   r4   r5   f  s    zAbstractLine.all_statusesc             C   s   | j j| jf S )zO
        Return all possible statuses that this order line can move to
        )r0   r6   r7   )r8   r3   r3   r4   r9   m  s    zAbstractLine.available_statusesc             C   s^   || j krdS | j }|| j kr:tjtd|| j d || _ | j  tj| | ||d dS )z
        Set a new status for this line

        If the requested status is not valid, then ``InvalidLineStatus`` is
        raised.
        NzE'%(new_status)s' is not a valid status (current status: '%(status)s'))r:   r7   )r<   rF   r>   r:   )r7   r9   r   ZInvalidLineStatusr?   rC   r   rD   )r8   r:   r>   r3   r3   r4   rG   s  s    
zAbstractLine.set_statusc             C   sN   | j }g }x(| jj D ]}|jd|j|jf  qW |rJd|dj|f }|S )zf
        Returns a description of this line including details of any
        line attributes.
        z	%s = '%s'z%s (%s)z, )r   
attributesrB   appendr   valuejoin)r8   descops	attributer3   r3   r4   description  s    zAbstractLine.descriptionc             C   s   | j | j S )N)rO   line_price_incl_tax)r8   r3   r3   r4   r\     s    zAbstractLine.discount_incl_taxc             C   s   | j | j S )N)rR   line_price_excl_tax)r8   r3   r3   r4   r_     s    zAbstractLine.discount_excl_taxc             C   s   | j | j S )N)r   r   )r8   r3   r3   r4   line_price_tax  s    zAbstractLine.line_price_taxc             C   s   | j | j S )N)unit_price_incl_taxunit_price_excl_tax)r8   r3   r3   r4   unit_price_tax  s    zAbstractLine.unit_price_taxc             C   s   | j }|sdS g }d}x\tt|j D ]H}|d | jkrR|j|d  |d }q(|jd|d |d | jf  q(W |t|j d d kr|S dj|S )zN
        Returns a string summary of the shipping status of this line
        r*   Nrd   rk   z%s (%d/%d items)r   z, )shipping_event_breakdownreversedr/   valuesrd   r   r   )r8   
status_maprp   Zlast_complete_event_nameZ
event_dictr3   r3   r4   rt     s    
zAbstractLine.shipping_statusc             C   s   | j |}|| | jkS )z
        Test whether a shipping event with the given quantity is permitted

        This method should normally be overriden to ensure that the
        prerequisite shipping events have been passed for this line.
        )shipping_event_quantityrd   )r8   rj   rd   current_qtyr3   r3   r4   is_shipping_event_permitted  s    

z(AbstractLine.is_shipping_event_permittedc             C   s4   | j j|djtd}|d dkr(dS |d S dS )zy
        Return the quantity of this line that has been involved in a shipping
        event of the passed type.
        )event__event_typerd   quantity__sumNr   )shipping_event_quantitiesr   	aggregater	   )r8   rj   resultr3   r3   r4   r     s
    z$AbstractLine.shipping_event_quantityNc             C   s   |s
| j }| j||kS )zJ
        Test whether this line has passed a given shipping event
        )rd   r   )r8   rj   rd   r3   r3   r4   has_shipping_event_occurred  s    z(AbstractLine.has_shipping_event_occurredc             C   s   |j j| dS )z
        Fetches the ShippingEventQuantity instance for this line

        Exists as a separate method so it can be overridden to avoid
        the DB query that's caused by get().
        )rF   )rm   r6   )r8   rr   r3   r3   r4   get_event_quantity  s    zAbstractLine.get_event_quantityc             C   sd   t  }xX| jj D ]J}|j}|j}| j|j}||krL|| d  |7  < q|||d||< qW |S )zS
        Returns a dict of shipping events that this line has been through
        rd   )rj   rk   rd   )r   rg   rB   rj   rk   r   rd   )r8   r   rr   rj   rs   r|   r3   r3   r4   r     s    z%AbstractLine.shipping_event_breakdownc             C   s   | j |}|| | jkS )z
        Test whether a payment event with the given quantity is permitted.

        Allow each payment event type to occur only once per quantity.
        )payment_event_quantityrd   )r8   rj   rd   r   r3   r3   r4   is_payment_event_permitted  s    
z'AbstractLine.is_payment_event_permittedc             C   s4   | j j|djtd}|d dkr(dS |d S dS )zx
        Return the quantity of this line that has been involved in a payment
        event of the passed type.
        )r   rd   r   Nr   )payment_event_quantitiesr   r   r	   )r8   rj   r   r3   r3   r4   r     s
    z#AbstractLine.payment_event_quantityc             C   s
   | j d kS )N)r   )r8   r3   r3   r4   is_product_deleted   s    zAbstractLine.is_product_deletedc             C   s   | j sdtdd| ji fS y|jj| j d}W n  |jjjk
rP   | j}Y nX |j| j }|j| j }|j	j
|d\}}|sd|fS dS )	zb
        Test if this line can be re-ordered using the passed strategy and
        basket
        Fz"'%(title)s' is no longer availabler   )r   )rd   TN)TN)r   r?   r   rA   r6   modelDoesNotExistrd   Zfetch_for_productZavailabilityZis_purchase_permitted)r8   r   ZstrategyZbasket_lineZdesired_qtyr   Zis_availablereasonr3   r3   r4   is_available_to_reorder$  s    z$AbstractLine.is_available_to_reorder)N)>r   r   r   r   r   r   r   r?   r=   r   partnerr   Zpartner_nameZpartner_skuZpartner_line_referencer   Zpartner_line_notesZstockrecordr   r   r   ZupcPositiveIntegerFieldrd   r   r   r   rO   rR   Zunit_cost_pricer   r   Zunit_retail_pricer7   	DateFieldest_dispatch_dater   r   r0   r   r   r   r5   r9   rG   r   r   r   r\   r_   r   r   rt   r   r   r   r   r   r   r   r   r  r3   r3   r3   r4   r     s   	










		r   c               @   s|   e Zd ZdZejdejdeddZejddej	ded	d
Z
ejedddZejedddZG dd dZdd ZdS )AbstractLineAttributez 
    An attribute of a line
    z
order.Liner   Line)r   r$   r   zcatalogue.OptionTZline_attributesOption)r   r   r$   r   Typer   )r   Valuer   c               @   s$   e Zd ZdZdZedZedZdS )zAbstractLineAttribute.MetaTr=   zLine AttributezLine AttributesN)r   r   r   r   r   r?   r   r   r3   r3   r3   r4   r   K  s   r   c             C   s   d| j | jf S )Nz%s = %s)r   r   )r8   r3   r3   r4   r   Q  s    zAbstractLineAttribute.__str__N)r   r   r   r   r   r   r   r?   rF   r   optionr   r   r   r   r   r3   r3   r3   r4   r  <  s   r  c               @   s   e Zd ZdZejdejdeddZejdejde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dZejedddddZG dd dZdd ZdS )AbstractLinePricea  
    For tracking the prices paid for each unit within a line.

    This is necessary as offers can lead to units within a line
    having different prices.  For example, one product may be sold at
    50% off as it's part of an offer while the remainder are full price.
    zorder.OrderZline_pricesr	  )r   r$   r   z
order.Linepricesr  r   r   )r&   zPrice (inc. tax)r'   r%   )r(   r)   zPrice (excl. tax)zShiping (inc. tax)r   )r(   r)   r&   zShipping (excl. tax)c               @   s(   e Zd ZdZdZdZedZedZdS )zAbstractLinePrice.MetaTr=   idz
Line PricezLine PricesN)r  )	r   r   r   r   r   r   r?   r   r   r3   r3   r3   r4   r   q  s
   r   c             C   s   t d| j| j| jd S )Nz4Line '%(number)s' (quantity %(qty)d) price %(price)s)r;   r   price)r?   rF   rd   price_incl_tax)r8   r3   r3   r4   r   x  s    zAbstractLinePrice.__str__N)r   r   r   r   r   r   r   r?   r=   rF   r  rd   r   r  Zprice_excl_taxrU   rX   r   r   r3   r3   r3   r4   r  U  s,   r  c               @   sN   e Zd ZdZejeddddZeedddddZ	G d	d
 d
Z
dd ZdS )AbstractPaymentEventTypez}
    Payment event types are things like 'Paid', 'Failed', 'Refunded'.

    These are effectively the transaction types.
    Namer   T)r   r   Coderk   )r   r   populate_fromc               @   s(   e Zd ZdZdZedZedZdZdS )zAbstractPaymentEventType.MetaTr=   zPayment Event TypezPayment Event Typesrk   N)rk   )	r   r   r   r   r   r?   r   r   r   r3   r3   r3   r4   r     s
   r   c             C   s   | j S )N)rk   )r8   r3   r3   r4   r     s    z AbstractPaymentEventType.__str__N)r   r   r   r   r   r   r?   rk   r   coder   r   r3   r3   r3   r4   r    s   r  c               @   s   e Zd Z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ddeddZejdejeddZejddejddZejedddZG dd dZdd Zdd ZdS ) AbstractPaymentEventz}
    A payment event for an order

    For example:

    * All lines have been paid for
    * 2 lines have been refunded
    zorder.OrderZpayment_eventsr}   )r   r$   r   Amountr'   r%   )r(   r)   	Referencer   T)r   r!   z
order.LinePaymentEventQuantityLines)throughr   zorder.PaymentEventTypez
Event Type)r   r   zorder.ShippingEvent)r   r   r$   zDate created)r   c               @   s*   e Zd ZdZdZedZedZdgZdS )zAbstractPaymentEvent.MetaTr=   zPayment EventzPayment Eventsz-date_createdN)	r   r   r   r   r   r?   r   r   r   r3   r3   r3   r4   r     s
   r   c             C   s   t d| j S )NzPayment event for order %s)r?   r=   )r8   r3   r3   r4   r     s    zAbstractPaymentEvent.__str__c             C   s   | j j j S )N)rA   rB   rb   )r8   r3   r3   r4   num_affected_lines  s    z'AbstractPaymentEvent.num_affected_linesN)r   r   r   r   r   r   r   r?   r=   r   rw   r   	referenceManyToManyFieldrA   rj   shipping_eventr   r   r   r   r  r3   r3   r3   r4   r    s4   r  c               @   s\   e Zd ZdZejdejdeddZejdejdeddZ	ej
ed	ZG d
d dZdS )r  z;
    A "through" model linking lines to payment events
    zorder.PaymentEventrm   Event)r   r$   r   z
order.Liner   r  r   c               @   s$   e Zd ZdZedZedZdZdS )zPaymentEventQuantity.Metar=   zPayment Event QuantityzPayment Event Quantitiesrr   rF   N)rr   rF   )r   r   r   r   r?   r   r   unique_togetherr3   r3   r3   r4   r     s   r   N)r   r   r   r   r   r   r   r?   rr   rF   r  rd   r   r3   r3   r3   r4   r    s   r  c               @   s   e Zd ZdZejdejdeddZej	dddedd	Z
ejd
eje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dS )AbstractShippingEventzf
    An event is something which happens to a group of lines such as
    1 item being dispatched.
    zorder.Orderrg   r}   )r   r$   r   z
order.LineShippingEventQuantityr  )r$   r  r   zorder.ShippingEventTypez
Event Type)r   r   zEvent notesTz:This could be the dispatch reference, or a tracking number)r!   r   zDate Created)r   c               @   s*   e Zd ZdZdZedZedZdgZdS )zAbstractShippingEvent.MetaTr=   zShipping EventzShipping Eventsz-date_createdN)	r   r   r   r   r   r?   r   r   r   r3   r3   r3   r4   r     s
   r   c             C   s   t d| jj| jd S )Nz Order #%(number)s, type %(type)s)r;   r   )r?   r=   r;   rj   )r8   r3   r3   r4   r     s    zAbstractShippingEvent.__str__c             C   s
   | j j S )N)rA   rb   )r8   r3   r3   r4   r    s    z(AbstractShippingEvent.num_affected_linesN)r   r   r   r   r   r   r   r?   r=   r  rA   rj   r   r   r   r   r   r   r  r3   r3   r3   r4   r#    s(   r#  c                   st   e Zd ZdZejdejdeddZejdejdeddZ	ej
ed	ZG d
d dZ fddZdd Z  ZS )r$  z
    A "through" model linking lines to shipping events.

    This exists to track the quantity of a line that is involved in a
    particular shipping event.
    zorder.ShippingEventrm   r!  )r   r$   r   z
order.Liner   r  r   c               @   s$   e Zd ZdZedZedZdZdS )zShippingEventQuantity.Metar=   zShipping Event QuantityzShipping Event Quantitiesrr   rF   N)rr   rF   )r   r   r   r   r?   r   r   r"  r3   r3   r3   r4   r     s   r   c                s<   | j s| jj | _ | jj| jj| j s*tjt j|| d S )N)	rd   rF   r   rr   rj   r   ZInvalidShippingEventr   rC   )r8   r   r   )r   r3   r4   rC   $  s    
zShippingEventQuantity.savec             C   s   t d| jj| jd S )Nz%(product)s - quantity %(qty)d)r   r   )r?   rF   r   rd   )r8   r3   r3   r4   r   .  s    zShippingEventQuantity.__str__)r   r   r   r   r   r   r   r?   rr   rF   r  rd   r   rC   r   r   r3   r3   )r   r4   r$    s   
r$  c               @   sN   e Zd ZdZejeddddZeeddddd	Z	G d
d dZ
dd ZdS )AbstractShippingEventTypezZ
    A type of shipping/fulfillment event

    Eg: 'Shipped', 'Cancelled', 'Returned'
    r  r   T)r   r   r  r   rk   )r   r   r  c               @   s(   e Zd ZdZdZedZedZdZdS )zAbstractShippingEventType.MetaTr=   zShipping Event TypezShipping Event Typesrk   N)rk   )	r   r   r   r   r   r?   r   r   r   r3   r3   r3   r4   r   @  s
   r   c             C   s   | j S )N)rk   )r8   r3   r3   r4   r   G  s    z!AbstractShippingEventType.__str__N)r   r   r   r   r   r   r?   rk   r   r  r   r   r3   r3   r3   r4   r%  4  s   r%  c                   s\  e Zd ZdZejdejdeddZd.\Z	Z
Ze	ee	fe
ee
feeeffZejed	e	d
edZejedd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ddZejedddZejedddddZejddZedd Zedd Zed d! ZG d"d# d#Z fd$d%Zd&d' Zed(d) Z ed*d+ Z!d,d- Z"  Z#S )/r   am  
    A discount against an order.

    Normally only used for display purposes so an order can be listed with
    discounts displayed separately even though in reality, the discounts are
    applied at the line level.

    This has evolved to be a slightly misleading class name as this really
    track benefit applications which aren't necessarily discounts.
    zorder.Orderr   r}   )r   r$   r   r    ShippingDeferredzDiscount category@   )r&   r   choiceszOffer IDT)r!   r   z
Offer namer   )r   r   r!   z
Voucher IDr  Z	Frequency)r   r  r'   r%   r   )r(   r)   r&   )r!   c             C   s   | j | jkS )N)r   r   )r8   r3   r3   r4   is_basket_discount{  s    z(AbstractOrderDiscount.is_basket_discountc             C   s   | j | jkS )N)r   r   )r8   r3   r3   r4   is_shipping_discount  s    z*AbstractOrderDiscount.is_shipping_discountc             C   s   | j | jkS )N)r   r   )r8   r3   r3   r4   is_post_order_action  s    z*AbstractOrderDiscount.is_post_order_actionc               @   s$   e Zd ZdZdZedZedZdS )zAbstractOrderDiscount.MetaTr=   zOrder DiscountzOrder DiscountsN)r   r   r   r   r   r?   r   r   r3   r3   r3   r4   r     s   r   c                sR   | j r | j r | j}|r |j| _| jr@| j r@| j}|r@|j| _t j	f | d S )N)
offer_id
offer_nameofferrk   
voucher_idvoucher_codevoucherr  r   rC   )r8   r   r/  r2  )r   r3   r4   rC     s    zAbstractOrderDiscount.savec             C   s   t d| j| jd S )Nz+Discount of %(amount)r from order %(order)s)rw   r=   )r?   rw   r=   )r8   r3   r3   r4   r     s    zAbstractOrderDiscount.__str__c             C   s6   t dd}y|jj| jdS  |jk
r0   d S X d S )Nr/  ZConditionalOffer)r  )r   objectsr6   r-  r   )r8   Offerr3   r3   r4   r/    s
    
zAbstractOrderDiscount.offerc             C   s6   t dd}y|jj| jdS  |jk
r0   d S X d S )Nr2  Voucher)r  )r   r3  r6   r0  r   )r8   r5  r3   r3   r4   r2    s
    
zAbstractOrderDiscount.voucherc             C   s   | j r| j S | jpdS )Nr*   )r1  r.  )r8   r3   r3   r4   r     s    z!AbstractOrderDiscount.description)r    r&  r'  )$r   r   r   r   r   r   r   r?   r=   r   r   r   ZCATEGORY_CHOICESr   r   r  r-  r.  r0  r1  Z	frequencyr   rw   r   r   r   r*  r+  r,  r   rC   r   r/  r2  r   r   r3   r3   )r   r4   r   N  sD   




r   ):r   loggingcollectionsr   decimalr   rN   django.confr   django.core.exceptionsr   Zdjango.core.signingr   r   	django.dbr   django.db.modelsr	   django.utilsr
   django.utils.cryptor   Zdjango.utils.timezoner   django.utils.translationr   r?   r   Zoscar.apps.order.signalsr   r   Zoscar.core.compatr   oscar.core.loadingr   oscar.core.utilsr   oscar.models.fieldsr   r*   r   	getLoggerr   Modelr   r   r   r   r   r  r  r  r  r  r#  r$  r%  r   r3   r3   r3   r4   <module>   sL   
  k0  P-3')