o
    -h+u                     @   sp  d dl Z d dlZe eZd dlmZ d dlmZ d dl	m
Z
 d dlmZmZ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mZmZ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*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1 d dlmZ d dl2Z2d dl3m4Z4 d dl5m6Z6 d dl7m8Z8 d dlm9Z9 d dl:Z:e dZedddd Z;edddd  Z<eddd!d" Z=e4ej>edded#d$gd%d& Z?d'd( Z@d)d* ZAd+d, ZBd-d. ZCd/d0 ZDd1d2 ZEd3d4 ZFeddd5d6 ZGeddd7d8 ZHeddd9d: ZIeddej>d;d< ZJeddej>d=d> ZKdS )?    N)Decimal)	Paginator)modelformset_factory)renderget_object_or_404redirect)JsonResponseHttpResponse)login_required)transaction)	timedelta)datetime)require_http_methods)SumCountQFDecimalField)
TruncMonthCoalesce)PermissionDenied   )SaleFormSaleItemForm)SaleSaleItem)Product)Customer)Shop)r   )csrf_exempt)timezone)messages)	localtimesalesz/auth/login/)	login_urlc                 C   sv  z%t   }|t| d }|jdd}|tdd }|tdd }W n% tyJ } ztd|  t	| di i i dd	W  Y d }~S d }~ww z2t
jj|d
jtdtdtdddtdtdddtdtdddtdtdddtdd}W n# ty } ztd|  ddddddd}W Y d }~nd }~ww t
jj|djtdtdtdddtdtdddtdtdddtdtdddd}|tdd }	t
jj|	|djtddd pd}
d}|
dkr|d pd|
 |
 d }t
jj|djtdtdtdddtdtdddtdtdddtdtdddd}t
jj|djtddd jtdtdtdddtdtdddtdtdddtdtddddd }t
jjddjtdttd!td"t d# d$jdd%}|jtd&dd pd}|d'  }t
jjd|d(jtdttd!td"t d# d)jdd*d'd+}|jtd,dd pd}t
j d'd-d d. }t
jjdd t
jjdd/d0 t
jjdd1d0 t
jjdd1d0tdd2 pdd3}d4}d}|dkr|d pd| d }|||t|||d5 p!dt|dt|d|||d d6 ||d7}t	| d|S )8N)daysr   )day      z&Error in dashboard date calculations: zsales/sale_dashboard.htmlz6Unable to load dashboard data. Please try again later.)daily_salesweekly_salesmonthly_saleserror_message)sale_date__datetotal_amountcashpayment_method)filtermpesacreditchequeid)total_sales
cash_salesmpesa_salescredit_salescheque_salestransaction_countzError calculating daily sales: r   sale_date__date__gte)r7   r8   r9   r:   r;      )r>   sale_date__date__lt)totalrA   r7   d   	sale_date)monthrD   credit_amount0)output_field)outstanding)outstanding__gtrH   customer)r1   r@   )outstanding_amount)outstanding_amount__gtz-outstanding_amountrK   
-sale_date
   T)r1   cheque_clearedFtotal_amount__sum)total_chequescleared_chequespending_chequespending_amounti r<      )r)   r*   r+   six_months_salescheque_statsdaily_transactionsweekly_growthmonthly_target_percentagetotal_outstanding_creditcustomers_with_debtoverdue_debtstotal_overdue_amountrecent_sales)r    nowdater   weekdayreplace	Exceptionloggererrorr   r   objectsr2   	aggregater   r   r   annotater   valuesorder_byr   r   r   r   distinctcountselect_relatedalllistround)requesttodaystart_of_weekstart_of_monthsix_months_agotwo_weeks_agoer)   r*   prev_week_startprev_week_salesrY   r+   rV   credit_sales_with_balancer[   r\   r]   r^   r_   rW   monthly_targetrZ   context r~    /var/www/html/pos/sales/views.py	dashboard$   s  
		


r   c                 C   s  t j ddd}| jdd }|r=|t	|dt	|dB t	|dB t	|d	B t	|d
B t	|dB t	|dB }| jdd}|rL|j|d}| jdd}| jdd}|rvzt
|d }|j|d}W n	 tyu   Y nw |rzt
|d }|j|d}W n	 ty   Y nw | jddkrtdd}d|d< t|}	|	g d |D ]5}
|
jr|
jj d|
jj nd}|	|
j|
jd||
j|
 |
jrdnd|
jj|
jpd|
jpdg	 q|S t|d }| jd!}| |}d"|i}t!| d#|S )$NrJ   userrM   search )id__icontains)customer__first_name__icontains)customer__last_name__icontains)customer__phone__icontains)mpesa_reference__icontains)cheque_number__icontains)user__username__icontainsr1   r0   	date_fromdate_to%Y-%m-%dr=   )sale_date__date__lteexportcsvztext/csv)content_typez%attachment; filename="sales_list.csv"zContent-Disposition)	zSale IDDater   AmountzPayment MethodStatusz	Served ByzMpesa ReferencezCheque Number zWalk-inz%Y-%m-%d %H:%MCompletePending   pager#   zsales/sales_list.html)"r   rg   ro   rn   rk   GETgetstripr2   r   r   strptimera   
ValueErrorr	   r   writerwriterowrJ   
first_name	last_namer6   rC   strftimer.   get_payment_method_displayis_completer   usernamempesa_referencecheque_numberr   get_pager   )rr   r#   search_queryr1   r   r   	from_dateto_dateresponser   salecustomer_name	paginatorpage_numberpage_objr}   r~   r~   r   
sales_list   s|   

 


r   c                 C   s0   t t|d}tjj|d}||d}t| d|S )Nr6   r   )r   
sale_itemszsales/sale_detail.html)r   r   r   rg   r2   r   )rr   sale_idr   r   r}   r~   r~   r   sale_detail  s   r   r   POSTc              
   C   s   | j dkrt| dtj | jdS zt| j}d|v r#t	| |W S t
| |W S  tjy;   tddddd	 Y S  tyW } ztdt|dd
d	W  Y d }~S d }~ww )Nr   zsales/make_sale.html)shopr   queryrf   zInvalid JSONstatusmessage  r     )methodr   r   rg   firstr   jsonloadsbodyhandle_live_search_with_tenantprocess_saleJSONDecodeErrorr   rd   str)rr   datarx   r~   r~   r   	make_sale  s    
"r   c                 C   s   |d   }|ddkr*tjt|dt|dB d d }tddd	 |D iS |dd
krRtjjddt|dt|dB d d }tddd	 |D iS tdddddS )Nr   typerJ   name__icontainsphone__icontainsrN   	customersc                 S   s   g | ]}|j |j|jd qS )r6   namephoner   ).0cr~   r~   r   
<listcomp>4  s    z2handle_live_search_with_tenant.<locals>.<listcomp>productr   )stock_quantity__gtbarcode__icontainsproductsc                 S   s&   g | ]}|j |jt|j|jd qS ))r6   r   pricestock)r6   r   r   selling_pricestock_quantity)r   pr~   r~   r   r   ?  s    rf   zInvalid search typer   r   r   )r   r   r   rg   r2   r   r   r   )rr   r   r   r   r   r~   r~   r   r   +  s.   



r   c              
   C   s  | d }stdddddS | dg }|s!tdddddS d }| d	 }rGz	tjj |d
}W n tjyF   tddddd Y S w tdd |D }tdd |D }d}|D ]D}	|	d dkr|	 dddkrd}|s|tddddd  S t|drt|dd}
tt	|	d }|
| |j
krtddddd  S q]|r||k rtdd |D |d }n|rt|dd dn|d }t| ||||}ddlm} |D ][}	|	 dddkr.||	d tt	|	d d }|	d d!kr|	 d"i  d#r|	d" d# |d#< n|	d d$kr%|	 d"r%|	d"  d%|d%< |	d"  d&|d&< |jjd*i | qzt|| W n" tyX } z|  tdt	|dddW  Y d }~S d }~ww td'|jt	|jt	|t	t|| td(d)S )+Nitemsrf   zNo sale items providedr   r   r   payment_methodszNo payment methods providedcustomer_idr   zCustomer not foundi  c                 s   ,    | ]}t t|d  t|d  V  qdS r   quantityNr   r   intr   itemr~   r~   r   	<genexpr>\  s   * zprocess_sale.<locals>.<genexpr>c                 s   0    | ]}| d ddkrtt|d  V  qdS amountr   Nr   r   r   r   r   r~   r~   r   r   ]     . Fr   r4   r   r   T"Customer required for credit salescredit_limitcurrent_credit_balanceCustomer credit limit exceededc                 s        | ]}|d  dkr|V  qdS )r   r4   Nr~   r   mr~   r~   r   r   q      c                 S   s   |  ddS )Nr   r   )r   )xr~   r~   r   <lambda>t  s    zprocess_sale.<locals>.<lambda>)keyr   )SalePayment)r   r1   r   r3   detailsr   r5   r   cheque_datesuccessrF   )r   r   r.   
total_paidbalance_duer~   )r   r   r   rg   DoesNotExistsumhasattrgetattrr   r   r   nextmax create_multi_payment_sale_recordmodelsr   createprocess_sale_itemsr   deleter6   r.   )rr   r   r   r   rJ   r   r.   r  
has_creditr   current_creditrE   primary_methodr   r   payment_datarx   r~   r~   r   r   H  st   
""r   c                 C   s  |dkrt | ddt | d k rtddddd	S d S |d
kr1| ds/tddddd	S d S |dkrf| dr?| dsHtddddd	S zt| d d W d S  tye   tddddd	 Y S w |dkr|sutddddd	S |t | d stddddd	S d S )Nr/   
cash_givenr   r.   rf   zInsufficient cash providedr   r   r   r3   r   zM-Pesa reference requiredr5   r   r  zCheque number and date requiredr   z0Invalid cheque date format (YYYY-MM-DD required)r4   r   r   )r   r   r   r   r   r   can_purchase_on_credit)r   r1   rJ   r~   r~   r   validate_payment_method  sj   &

r  c                 C   s\  t dd |d D }t dd |D }|||d | j||kd}|d dkr@t dd |D }||t|| td	d
 ne|d dkrdtdd |D d }	|	rc|	di drc|	d d |d< nA|d dkrtdd |D d }
|
r|
dr||
d d|
d dd n|d dkrt dd |D }||d< d|d< tjj	di |S )Nc                 s   r   r   r   r   r~   r~   r   r     s
    
z3create_multi_payment_sale_record.<locals>.<genexpr>r   c                 s   r   r   r   r   r~   r~   r   r     r   r   rJ   r.   r1   r   r   r/   c                 s   s<    | ]}|d  dkr| dddkrtt|d V  qdS )r   r/   r   r   Nr   r   r~   r~   r   r        : rF   r  
change_duer3   c                 s   r   )r   r3   Nr~   r   r~   r~   r   r     r   r   r   r5   c                 s   r   )r   r5   Nr~   r   r~   r~   r   r     r   r   r  r   r  r4   c                 s   s<    | ]}|d  dkr| dddkrtt|d V  qdS )r   r4   r   r   Nr   r   r~   r~   r   r     r  rE   Fr   r~   )
r  r   updater
  r   r	  r   r   rg   r  )rr   r   rJ   r  r   r.   r  	sale_datacash_amountmpesa_methodcheque_methodcredit_paid_nowr~   r~   r   r    sD   	
r  c                 C   s   t dd |d D }|||| j|dkd}|dkr-|t|d t|d | d n*|d	kr8|d
 |d
< n|dkrI||d |d d n|dkrWt|dd|d< tjjdi |S )Nc                 s   s(    | ]}t |d  t|d  V  qdS r   )r   r   r   r~   r~   r   r     s
    
z%create_sale_record.<locals>.<genexpr>r   r4   r  r/   r  r  r3   r   r5   r   r  r  credit_paidr   rE   r~   )r  r   r  r   r   r   rg   r  )rr   r   rJ   r1   r.   r  r~   r~   r   create_sale_record  s0   	


r#  c              	   C   s   |D ]E}t j j|d d}t|d }|j|k r"td|j t| ||t	|d t	|d | d}t
t|  | j|8  _|  qd S )N
product_idr   r   zInsufficient stock for r   )r   r   r   r   subtotal)r   rg   select_for_updater   r   r   r   r   r   r   supersave)r   r   r   r   r   	sale_itemr~   r~   r   r    s    

	
r  c                 C   s   t d}dt| j|iS )NzAfrica/NairobirC   )pytzr    r"   rC   )r   
nairobi_tzr~   r~   r   get_receipt_data/  s   
r,  c                 C   s   t t|d}|j }|jdkr|j}|j|j }nd }d}tj	 |||j|j|||j
|j|j|jj|jd|jrF|jj d|jj nd|jrN|jjnd|jdkrW|jnd d}t| d	|S )
Nr   r4   r   z%Y-%m-%d %H:%M:%Sr   zN/Ar5   )r   r   r   r.   r1   r"  r  r  r  r   	served_byrC   r   customer_phoner   zsales/receipt.html)r   r   r   ro   r1   rE   r.   r   rg   r   r  r  r   r   r   rC   r   rJ   r   r   r   r   r   )rr   r   r   r   r"  r  r}   r~   r~   r   receipt_view7  s0   


r/  c                 C   sP   | j dd  }tjt|dt|dB ddddd	}t	t
|d
dS )Nqr   r   r   r6   r   barcoder   r   Fsafe)r   r   r   lowerr   rg   r2   r   rj   r   rp   )rr   r   r   r~   r~   r   search_productsX  s   r5  c                 C   sX   | j dd  }tjt|dt|dB t|dB dddd	}t	t
|d
dS )Nr0  r   )first_name__icontains)last_name__icontainsr   r6   r   r   r   Fr2  )r   r   r   r4  r   rg   r2   r   rj   r   rp   )rr   r   r   r~   r~   r   search_customersa  s   r8  c              
   C   s  t t|d}tttddd}| jdkr| jddkrkz2t	| j
}t|d|j|_|d	|j|_|d
}|rBt t|d|_|  tdddW S  tyj } ztdt|dddW  Y d }~S d }~ww t| j|d}|| jtjj|dd}| r| r|  |jdd}	|	D ]#}
tjj|
jd}|j|
j }|
jj j|7  _|
jj  |
  qtdS tdddS | jddkrt|j|j|jr|jjnd d}t|S t|d}|tjj|dd}|||d}t| d|S )Nr   r   T)formextra
can_deleter   x-requested-withXMLHttpRequestr.   r1   r   r  zSale updated successfully!r   rf   r   r   )instancer   )querysetF)commitr   zInvalid form data)r.   r1   r   )r   	sale_formr   zsales/update_sale.html) r   r   r   r   r   r   headersr   r   r   r   r   r.   r1   r   rJ   r(  r   rd   r   r   r   rg   r2   is_validr6   r   batchr   r   r   r   )rr   r   r   SaleItemFormSetr   r   rx   rA  sale_item_formsetr   r   original_itemstock_adjustmentr}   r~   r~   r   update_salej  sV   

"

rI  c              
   C   s  t t|d}| jdkrz|j D ]}|j}| j|j7  _|  t	
d|j d|j d q|jdkrU|jrU|jrUt|jdrUt|jj|j td|j_|j  |j   |j}|  t	
d	| d
 | jddkrtdd	| d
dW S t| d tdW S  ty } z;t	d| dt|  | jddkrtdt|dddW  Y d }~S t| dt|  tdW  Y d }~S d }~ww tddiddS )Nr   r   z	Restored z
 units of z	 to stockr4   r   rF   zSale #z deleted successfullyr<  r=  T)r  r   z8Sale deleted successfully and stock quantities restored.zsales:sales_listzError deleting sale #z: F)r  rf   r   r   zError deleting sale: rf   zInvalid request method.i  )r   r   r   r   ro   r   r   r   r(  re   infor   r1   rJ   rE   r  r
  r   r   paymentsr  r6   rB  r   r   r!   r  r   rd   rf   r   )rr   r   r   r   r   sale_numberrx   r~   r~   r   delete_sale  s@   


"rM  )Lloggingr   	getLogger__name__re   decimalr   django.core.paginatorr   django.formsr   django.shortcutsr   r   r   django.httpr   r	   django.contrib.auth.decoratorsr
   	django.dbr   django.utils.timezoner   r   django.views.decorators.httpr   django.db.modelsr   r   r   r   r   django.db.models.functionsr   r   django.core.exceptionsr   formsr   r   r  r   r   inventory.modelsr   customers.modelsr   settings.modelsr   r   django.views.decorators.csrfr   django.utilsr    django.contribr!   r"   r*  r   r   r   atomicr   r   r   r  r  r#  r  r,  r/  r5  r8  rI  rM  r~   r~   r~   r   <module>   sx   


 
N

U,+#
 

A