o
    wh                     @   s   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 d d	lmZmZ d d
lZeeZG dd dejZG dd dejZd
S )    )models)settings)ValidationError)transaction)Decimal)timezone)now)Customer)ProductBatchNc                       s*  e Zd Zg dZejeddejdZej	ddddZ
ejdedZejedd	Zejd
dZejejejdZej	dddddZej	dddddZejddddZej	dddddZejdddZejddddZejdddZejd
dZG dd dZdd Z dd Z! fddZ"e#dd Z$  Z%S )Sale))cashCash)mpesazM-Pesa)creditCredit)chequeChequeT)nullblank	on_delete
      r   )
max_digitsdecimal_placesdefault)
max_lengthchoices)r   db_indexF)r   r   )r   r   r   r      )r   r   r   )r   r   2   c                   @   s   e Zd ZdgZdS )z	Sale.Metaz
-sale_dateN)__name__
__module____qualname__ordering r&   r&   (/var/www/html/hyperkenya/sales/models.pyMeta/   s    
r(   c                 C   s   d| j  d| j d| j dS )NzSale #z - z ())idtotal_amountpayment_methodselfr&   r&   r'   __str__2   s   zSale.__str__c              	   C   s  | j dkr| jstd| j dkr| jstd| j dkr&| jdu r&td| j dkr| js2td	| js9td
| jra| jratj	j
| j| jddj| jrP| jndd}| ratd| j d| jr| jt  k rtd| j d| j d| j d dS dS dS dS )z&Validation for payment-specific fieldsr   z0Cash amount given is required for cash payments.r   zM-Pesa reference is required.r   Nz7Credit amount must be specified (use 0 for no deposit).r   zCheque number is required.zCheque date is required.)customercheque_numberr,   )r*   zCheque number z" already exists for this customer.zPast-dated cheque recorded: #z (Date: z
, Amount: r)   )r,   
cash_givenr   mpesa_referencecredit_amountr1   cheque_dater0   r   objectsfilterexcluder*   existsr   r   dateloggerwarningr+   )r.   existing_chequer&   r&   r'   clean5   s@   



z
Sale.cleanc                    sZ   |    | jdkr| jr| j| j | _| jdk| _n| jdv r"d| _t j|i | dS )zHandle payment completion logicr   r   )r   r   TN)
full_cleanr,   r2   r+   
change_dueis_completesupersaver.   argskwargs	__class__r&   r'   rC   Y   s   
z	Sale.savec                 C   s,   | j dkrt| j| jpd tdS tdS )z/Calculate remaining credit for partial paymentsr   r   )r,   maxr+   r4   r   r-   r&   r&   r'   outstanding_credith   s   
zSale.outstanding_credit)&r"   r#   r$   PAYMENT_METHOD_CHOICESr   
ForeignKeyr	   SET_NULLr0   DecimalFieldr+   	CharFieldr,   DateTimeFieldr   	sale_dateBooleanFieldrA   r   AUTH_USER_MODELCASCADEuserr2   r@   r3   r4   	DateFieldcredit_paid_dater1   r5   cheque_clearedr(   r/   r>   rC   propertyrJ   __classcell__r&   r&   rG   r'   r      s,    $r   c                       s   e Zd ZejedejdZejeej	dZ
ejeej	dddZe ZejdddZejddd	d
Zdd Z fddZdd Zdd Z  ZS )SaleItemitems)related_namer   r   T)r   r   r   r   r   )r   r   F)r   r   editablec                 C   s`   | j r| j| j jkrtd| j j d| j j | j s,| j| jjkr.td| jj ddS dS )zValidate stock availabilityzOnly z units available in batch z units availableN)batchquantityr   
batch_codeproductstock_quantityr-   r&   r&   r'   r>   x   s
   zSaleItem.cleanc                    st   | j s| jr
| jj n| jj | _ | j | j | _t  t j|i | | 	  W d   dS 1 s3w   Y  dS )z&Auto-calculate prices and update stockN)
selling_pricer_   rb   r`   subtotalr   atomicrB   rC   update_stockrD   rG   r&   r'   rC      s   

"zSaleItem.savec                 C   sB   | j r| j  j| j8  _| j   | j j| j8  _| j  dS )z'FIFO stock reduction with thread safetyN)r_   r`   rC   rb   rc   r-   r&   r&   r'   rg      s
   
zSaleItem.update_stockc                 C   s   | j  d| jj d| j S )Nzx z @ )r`   rb   namerd   r-   r&   r&   r'   r/      s   zSaleItem.__str__)r"   r#   r$   r   rL   r   rT   saler
   PROTECTrb   r   r_   PositiveIntegerFieldr`   rN   rd   re   r>   rC   rg   r/   rZ   r&   r&   rG   r'   r[   p   s    r[   )	django.dbr   django.confr   django.core.exceptionsr   r   decimalr   django.utilsr   django.utils.timezoner   customers.modelsr	   inventory.modelsr
   r   logging	getLoggerr"   r;   Modelr   r[   r&   r&   r&   r'   <module>   s    
_