o
    Yh                    @   sx  d dl mZmZ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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 d dl m!Z! d dl"m#Z# d dl$m%Z% d dl&m'Z' d dl(Z(d dl)Z)d dl*Z*d dl+Z+d dl,m-Z- d dl.m/Z/ ddl0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7m8Z8m9Z9m:Z:m;Z;m<Z< d dl=m>Z> d dl?m@Z@ d dlAmBZBmCZCmDZDmEZEmFZF d dlGmHZH d dlImJZJ d dlKmLZLmMZMmNZNmOZOmPZPmZmQZQmRZRmSZSmTZTmUZU d dlVmWZW d dlXmYZY d dlZm[Z[m\Z\m]Z] d dl^Z^e^_dZ`G dd  d e	eZaG d!d" d"e	e
eZbG d#d$ d$e	e
eZcG d%d& d&e	e
eZdG d'd( d(e	e
eZeG d)d* d*e	e
eZfG d+d, d,e	e
eZgG d-d. d.e	e
eZhG d/d0 d0e	e
eZiG d1d2 d2e	e
eZjG d3d4 d4e	e
eZkG d5d6 d6e	e
eZlG d7d8 d8e	e
eZmG d9d: d:e	e
eZneeeOd;d< Zod=d> ZpeeeOd?d@ ZqedAdB ZreeeOdCdD ZseeeOdEdF ZteeeOdGdH ZueeeOdIdJ ZvedKdL ZwedMdNdO ZxedMdPdQ ZyedRdSdT ZzdUdV Z{eeeOdWdX Z|eeeOdYdZ Z}eeeOd[d\ Z~eeeOd]d^ ZG d_d` d`eZG dadb dbe	eZG dcdd dde	eZdS )e    )renderget_object_or_404redirect)login_requireduser_passes_testpermission_required)LoginRequiredMixinUserPassesTestMixin)	LoginView)messages)ListView
DetailView
CreateView
UpdateView
DeleteViewTemplateView)reverse_lazyreverse)transaction)JsonResponseHttpResponse)View)csrf_exempt)	send_mail)settingsDecimalN)timezone	timedelta   )CustomerServiceCustomerTagCustomerInvitationCustomerBalanceTransaction)CustomerFormServiceFormCustomerTagFormCustomerBalanceFormCustomerServiceManagementFormSubAccountForm)get_user_model)	Paginator)QSumCountAvgF)appsInvoice)has_financial_accesscan_assign_ticketscan_delete_customersis_adminhas_management_privilegesr   EmployeeRequiredMixinAdminRequiredMixinManagementRequiredMixinhas_permissionget_user_permissions)PermissionDenied)wraps)CustomerActionServiceCustomerNotificationServiceCustomerServiceManagerzaccounts.loginc                       s   e Zd Z fddZdd Z fddZdd Zd	d
 Zdd Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd  Zd!d" Zd#d$ Z  ZS )%DashboardViewc                    s   t  j|g|R i |S N)superdispatch)selfrequestargskwargs	__class__ //var/www/html/optinet_system/customers/views.pyrH   1   s   zDashboardView.dispatchc                 C   sr   | j jjrdgS t| j jdr| j jjr| j jjjdkrdgS t| j jdr.| j jjr.dgS | j jjr6dgS dgS )Nzdashboard/dashboard.htmlemployee_profileactivezdashboard/staff_dashboard.htmlcustomer_profilez!dashboard/customer_dashboard.html)rJ   useris_superuserhasattrrQ   employment_statusrS   is_staffrI   rO   rO   rP   get_template_names6   s   

z DashboardView.get_template_namesc           "         s  t  jdi |}| jj}||d< t||d< |jrddlm} ddlm	} ddl
m} ddlm} dd	lm} dd
lm}	m}
 ddlm}m}m}m} ddlm} |	 }|jdd}|j |d< |jjdd |d< |jjdd |d< |jjdd |d< |jjd|j|j dj!|ddd pd|d< dd|jjdd dd|d < |jjd!d"d#gd$|d%< |jjd"d& |d'< d(|d)< |jj|d*d+gd,}| |d-< |j!|ddd pd|d.< |jj|d/ }|jj|dd0 }|dkr|| d1 nd|d2< |j"d3d d4 |d5< |jj|d6# d d7 |d8< g |d9< dd:l
m$} |jj%|d;d<"d=d d7 }||d9< d>d?d@dAdBd@dCdDd@dEdFd@dGdHd@dIdJd@g|dK< d>dLdMdAdNdMdCdOdMdEdPdMdGdQdMdIdRdMg|dS< dT|dU< dV|dW< zddXl
m&} |jjdYd& |dZ< W n   d|dZ< Y |jj|j|j d[j!|d\dd pd|d]< |d- t'|d%  |d^< nt(|d_r|j)r|j)j*dkrddlm	} ddlm} dd
lm}	m}
 dd`lm} |j)}||d_< |	 }|j+r|j+j,dakr5z!ddXl
m&} |jj|||
dbdc dd |de< dQ|df< dg|dh< W n   d|de< d|df< d|dh< Y n|j+j,dikrl|j||dj||dkB }|j|dl |dm< |jdn|do |dp< |jd"d#gdq |dr< n`|j+j,dskr|jjddt |du< zddvlm-} |jjdwdxdy |dz< W n9   d|dz< Y n0|j+j,d{krddlm} |jj|dd|j!|ddd pd|d}< |jj|d*d+gd, |d~< |j||dj||dkB }| |d< |jdnd& |d< |d dkr|d |d  d1 nd|d< |jj||dj||dkB |dl"d}g }|D ]C}|j.|j/|j0r$|j0j1nd|j2p2|j0r1|j0j3nd|j4|j5|6 |j7|j8t(|j7drO|j7oN|j7t9: k ndxd
}|;| q||d< |"dd d |d< |jdn||
dbdc d |d< t<d|d |d< |jd#d& |d< nFt(|dr|j=r|j=} | |d;< | j>"d3d d7 |d< | j?"d3d d7 |d< | j@|d< | j>jd*d+gdq}!|!j!|ddd pd|d< dr|vrd|dr< d|vrd|d< dp|vrd|dp< |S )NrT   user_permissionsr   r4   )Employeer    )r!   Ticket)Expense)dater   )r/   r0   r.   r1   r   daytotal_customersrR   service_statusactive_customers	suspendedsuspended_customerstrialtrial_customerspaidstatusupdated_at__monthupdated_at__yeartotal_amounttotalrr   total_revenuez99.9%onlineA   )uptimerouter_statusactive_connectionsbandwidth_utilizationnetwork_healthurgentopenin_progress)priority
status__inurgent_ticketsrm   open_tickets@avg_ticket_resolution_timependingoverdue)due_date__ltr   overdue_customersoverdue_amount)due_date__gte)r   rm   d   payment_collection_rate-created_at   recent_customers)invoices__in   overdue_customers_listservice_distribution)r"   customercustomer_count-customer_countJaniI monthrevenueFebi Mari q Apri Mayi@ Juni0 revenue_trend   r   new_customers               customer_growthg      !@customer_growth_rateg(@revenue_trend_rate)MarketingWeeklyReport	submittedpending_marketing_reports)expense_date__monthexpense_date__yearamountmonthly_expensescritical_issues_countrQ   )r.   	Marketing   days)
created_byweek_ending__gtereports_this_weekleads_generatedg     2@conversion_rate
Technician)assigned_employee)assigned_to)scheduled_date__datescheduled_todayclosed)rm   updated_at__datecompleted_todayr   pending_taskszHR Staff)rW   total_employees)PayslipTF)is_generatedis_paidpending_payslipszBilling Staff)date_paid__daterm   daily_collectionsoverdue_invoicestotal_ticketsclosed_ticketscompletion_ratescheduled_datezNo Customer r`   )
	ticket_idtitlecustomer_namecontact_phonelocationr~   get_priority_displayr   scheduled_end_timeis_past_duetodays_schedulez-updated_at
   recent_assignments)rm   updated_at__gtecompleted_weekU   monthly_progressin_progress_tasksrS   recent_invoicesrecent_ticketsaccount_balanceoutstanding_amountrO   )ArG   get_context_datarJ   rT   r?   rU   billing.modelsr5   	hr.modelsr\   modelsr!   tickets.modelsr^   expenditure.modelsr_   datetimer`   r   django.db.modelsr/   r0   r.   r1   decimalr   todayreplaceobjectscountfilterr   year	aggregateorder_bydistinctr"   annotater   lenrV   rQ   rW   
departmentnamer   r   r   r   	full_namer   phoner   r~   r   r   r   r   nowappendminrS   invoicesticketsr   )"rI   rL   contextrT   r5   r\   r!   r^   r_   r`   r   r/   r0   r.   r1   r   r   this_month_startr   total_invoicespaid_invoicesr"   servicesr   rQ   assigned_ticketsr   all_ticketstodays_ticketsschedule_listticketticket_datar   outstanding_invoicesrM   rO   rP   r   J   s  






"
" 



zDashboardView.get_context_datac                 C   s@   ddl m} |jjdt  djddd }t	jj|dS )	z#Get customers with overdue invoicesr   r4   unpaidrm   r   customer_idTflat)id__in)
r   r5   r   r   r   r  r`   values_listr   r!   )rI   r5   overdue_customer_idsrO   rO   rP   get_overdue_customersb  s   
z#DashboardView.get_overdue_customersc                 C   sN   ddl m} ddlm} |jjdt jt j	dj
|ddd p$d}|S )	zGet current month revenuer   r4   r/   rk   rl   rp   rq   rr   )r   r5   r   r/   r   r   r   r  r   r   r   )rI   r5   r/   r   rO   rO   rP   get_monthly_revenuek  s   z!DashboardView.get_monthly_revenuec           
      C   s   ddl m }m} ddlm} g }tdD ]H}t |d| d jdddddd}||d	d jdd
|dd }tj	j
d||gd}|j|ddd pNd}	||dt|	d qtt|S )zGet 6-month revenue trendr   )r   r   r  r      r   r    rb   hourminutesecondmicrosecond    ra   rk   )rm   updated_at__rangerp   rq   rr   %b %Yr   )r   r   r   r/   ranger   r  r   r5   r   r   r   r  strftimefloatlistreversed)
rI   r   r   r/   
trend_dataimonth_start	month_endmonthly_invoicesr   rO   rO   rP   get_revenue_trendx  s    & 
zDashboardView.get_revenue_trendc                 C   s   ddl m} g }tdD ];}t |d| d jdddddd}||dd jdd	|dd }tjj||gd
	 }|
|d|d qtt|S )z&Get customer growth over last 6 monthsr   r   r   r  r   r    r  r#  ra   )created_at__ranger%  r   )r   r   r&  r   r  r   r!   r   r   r   r  r'  r)  r*  )rI   r   growth_datar,  r-  r.  r   rO   rO   rP   get_customer_growth  s   & 
z!DashboardView.get_customer_growthc                 C   s8   ddl m} tjj|ddddddd	d
d S )z Get service package distributionr   )r0   r   r   r   
speed_mbpspricer   r   Nr   )r   r0   r"   r   r   valuesr   )rI   r0   rO   rO   rP   get_service_distribution  s   z&DashboardView.get_service_distributionc                 C   s   ddl m} ddlm} |jjt jt j	d}|j
tddd p'|d}|jd	d
j
tddd p9|d}|dkrFt|| d S dS )z'Calculate payment collection efficiencyr   r4   r   )issue_date__monthissue_date__yearrp   rq   rr   0rk   r   r   )r   r5   r   r   r   r   r   r  r   r   r   r/   r(  )rI   r5   r   r/  rp   paid_amountrO   rO   rP   get_payment_collection_rate  s   $z)DashboardView.get_payment_collection_ratec                 C   sj   ddl m} ddlm}m} |jjdddj|d|d d	j|d
dd }|r3t	|
 d dS dS )z+Get average ticket resolution time in hoursr   r]   )r1   r2   r   F)rm   completed_at__isnullcompleted_at
created_at)resolution_timer@  )avg_timerA  i  r    )r   r^   r   r1   r2   r   r   r   r   roundtotal_seconds)rI   r^   r1   r2   rA  rO   rO   rP   get_avg_ticket_resolution_time  s"   	z,DashboardView.get_avg_ticket_resolution_timec                 C   s   dt jjdd dddS )zGet network health indicatorsrt   T	is_activeru   z99.8%)rw   rx   ry   rv   )r!   r   r   r   rY   rO   rO   rP   get_network_health_status  s
   z'DashboardView.get_network_health_statusc                 C   sT   ddl m} ddlm}m} tjj|dtddd|dd	j	d
d
ddd S )z&Get top performing services by revenuer   r4   )r/   r0    customer__invoices__total_amountrk   )customer__invoices__status)r   r   )r   r   F)revenue__isnullz-revenueN   )r   r5   r   r/   r0   r"   r   r   r.   r   r   )rI   r5   r/   r0   rO   rO   rP   get_top_services  s   zDashboardView.get_top_servicesc                 C   s   ddl m} t jdddddd}||dd jdd}tjj|d }tjjd|t gd	 }|dkrAt	|| d
 dS dS )zCalculate monthly churn rater   r   r    r  r   ra   created_at__ltF)rF  r$  r      )
r   r   r   r  r   r!   r   r   r   rB  )rI   r   r-  prev_month_startcustomers_startchurnedrO   rO   rP   get_churn_rate  s   
zDashboardView.get_churn_ratec                 C   sX   z%t jjdd }|dkrW dS |  d }d|d  }tt|dd	W S    Y d
S )z8Calculate customer satisfaction based on various metricsTrE  r   g      @r   g      @g      ?r    g      @r   )r!   r   r   r   r<  r  rB  )rI   rc   payment_healthsatisfactionrO   rO   rP   get_customer_satisfaction_score  s   z-DashboardView.get_customer_satisfaction_scorec                 C   sz   z1ddl m} ddlm} |jjtddgdtt |dd d	B d
dgd	ddd }|W S  t
y<   g  Y S w )z Get urgent/high priority ticketsr   r]   r   highr{   )priority__in   )hoursrM  r|   r}   r   r   Nr   )r   r^   r   r   r   r   r.   r   r  select_relatedImportError)rI   r^   r   r   rO   rO   rP   get_urgent_tickets  s   z DashboardView.get_urgent_ticketsc                 C   s0   d}|   }|t|7 }|  }|t|7 }|S )z3Count critical issues requiring immediate attentionr   )r  r   r]  )rI   r   r   r   rO   rO   rP   get_critical_issues_count  s   z'DashboardView.get_critical_issues_countc                 C   sH   ddl m} ddlm} |jjdt  dj	|ddd p!d}|S )	zGet total amount overduer   r4   r  r  r  rp   rq   rr   )
r   r5   r   r/   r   r   r   r  r`   r   )rI   r5   r/   r   rO   rO   rP   get_overdue_amount.  s   
z DashboardView.get_overdue_amountc           
      C   s   ddl m} ddlm} ddlm} t jdddddd}||dd jdd}||dd }|j	j
d	|||d
d dj|ddd pGd}|j	j
d	||dj|ddd pZd}|dkrl|| | d }	t|	dS dS )z@Calculate revenue trend percentage for current vs previous monthr   r   r  r4   r    r  r   ra   rk   r#  )rm   r   updated_at__ltrp   rq   rr   )rm   r   updated_at__lter   )r   r   r   r/   r   r5   r   r  r   r   r   r   rB  )
rI   r   r/   r5   current_month
prev_monthprev_month_endcurrent_revenueprev_revenuetrendrO   rO   rP   get_revenue_trend_percentage:  s@   
z*DashboardView.get_revenue_trend_percentage)__name__
__module____qualname__rH   rZ   r   r  r  r0  r3  r7  r<  rD  rG  rL  rS  rV  r]  r^  r_  rh  __classcell__rO   rO   rM   rP   rE   /   s*      	
rE   c                       sT   e Zd ZeZdZdZdd Zdd Zdd Z	 fd	d
Z
 fddZdd Z  ZS )CustomerListViewcustomers/customer_list.html	customersc                 C   s   t | jjddS )Nper_pager   )intrJ   GETget)rI   querysetrO   rO   rP   get_paginate_by[     z CustomerListView.get_paginate_byc                 C      t | jjrdS | jjjrA| jjds"t| jjds"t| jjdr$dS t| jjdrA| jjjrA| jjjjrA| jjjjj	dkrAdS dS NTcustomers.view_customerview_customerview_customersrQ   r   F
r9   rJ   rT   rX   has_permr>   rV   rQ   r   r   rY   rO   rO   rP   	test_func^  "   

zCustomerListView.test_funcc                 C   s$  t jdd}| jjd}|r8|t|dt|dB t|dB t|dB t|dB t|d	B t|d
B }| jjd}|rG|j|d}| jjd}|rV|j|d}| jjd}|re|j|d}| jjdd}|dkrx|jdd}n|dkr|jdd}n
|dkr|jdd}|	dS )Nservicetagssearchfull_name__icontainscompany_name__icontains$contact_person_first_name__icontains#contact_person_last_name__icontainscustomer_id__icontainsphone__icontainsemail__icontainscustomer_typer  
service_idtagtags__id
status_taballrR   rd   inactiverg   r   )
r!   r   r[  prefetch_relatedrJ   rr  rs  r   r.   r   )rI   rt  r  r  r  tag_idr  rO   rO   rP   get_querysetr  sF   
zCustomerListView.get_querysetc                    s  t  jd%i |}tjdd}| jjd}|rA|	t
|dt
|dB t
|dB t
|dB t
|dB t
|d	B t
|d
B }| jjd}|rP|j	|d}| jjd}|r_|j	|d}| jjd}|rn|j	|d}| |d< |j	dd |d< |j	dd |d< |j	dd |d< tjj	dd|d< tj |d< | jjdd|d< | jjdd|d< | jjdd|d< | jjdd|d< | jjdd |d!< | jjd"d#k|d$< |S )&Nr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rc   rR   rd   rf   r  inactive_customersrg   rh   TrE  r
  r   current_servicecurrent_tagcurrent_customer_typer  r  current_status_tabX-Requested-WithXMLHttpRequestis_ajaxrO   )rG   r   r!   r   r[  r  rJ   rr  rs  r   r.   r   r"   r#   r  headers)rI   rL   r  base_querysetr  r  r  r  rM   rO   rP   r     sR   
z!CustomerListView.get_context_datac                    s"   | j jddkrdgS t  S )Nr  r  rn  )rJ   r  rs  rG   rZ   rY   rM   rO   rP   rZ     s   
z#CustomerListView.get_template_namesc                 O   s0  d|j v r|j dd }|st|d tdS |  }|j dd}|j dd}|d	kr8|jd
d}n6|dkrC|jdd}n+|dkrN|jdd}n |dkrY|jdd}n|dkrd|jdd}n
|dkrn|jdd}|rv|j|d}t|	 }|st|d tdS ddl
m}	 |	 }
d}d}|D ]!}|jr|
j|j||j|jd}|r|d7 }q|d7 }q|d7 }qddd d!d"d#d$d%}||d&}|rztjj|d'}|d(|j d)7 }W n
 tjy   Y nw |dkrt|d*| d+| d, |dkrt|d-| d. tdS | j|g|R i |S )/zHandle bulk SMS sendingsend_bulk_smsbulk_sms_messager   Please enter a message to send.customers:customer_listsms_audiencer  sms_tag_filteractive_onlyrR   rd   inactive_onlyr  individuals_only
individualr  institutions_onlyinstitutionwith_serviceF)service__isnullwithout_serviceTr  z;No customers found matching the selected audience criteria.r   NotificationServicephone_numbermessager  sent_byr    zall filtered customerszactive customerszinactive customerszindividual customerszinstitutional customerszcustomers with servicezcustomers without service)r  r  r  r  r  r  r  zselected customersidz with tag ""zBulk SMS sent successfully to  .zFailed to send SMS to z1 customers (missing phone numbers or SMS errors).)POSTrs  stripr   errorr   r  r   r)  r   notifications.servicesr  r   send_smsr  rT   r#   r   r   DoesNotExistsuccesswarning)rI   rJ   rK   rL   r  rt  r  r  ro  r  r  success_count
fail_countr   r  audience_descriptionsaudience_descr  rO   rO   rP   post  s   


	
zCustomerListView.post)ri  rj  rk  r!   modeltemplate_namecontext_object_nameru  r~  r  r   rZ   r  rl  rO   rO   rM   rP   rm  W  s    */rm  c                       sD   e Zd ZeZdZdZdZdZdd Z	 fddZ
 fdd	Z  ZS )
CustomerDetailViewcustomers/customer_detail.htmlr   r  c                 C   rw  rx  r|  rY   rO   rO   rP   r~  0  r  zCustomerDetailView.test_funcc                    sp   t  jdi |}| jj}| jjdd d }ddlm} |jj	| jddd d }|
|||d |S )	Nr   r   r   )Paymentr   r   )re   recent_transactionsrecent_paymentsrO   )rG   r   objectcurrent_service_statusbalance_transactionsr   payments.modelsr  r   r   update)rI   rL   r  re   r  r  r  rM   rO   rP   r   D  s   z#CustomerDetailView.get_context_datac                    s   |   | _d|jv rV|jdd }|s#t|d td| jjdS ddl	m
} | }|j| jj|| jj|jd	}|rHt|d
| jj  nt|d td| jjdS t j|g|R i |S )z,Handle SMS sending from customer detail pager  sms_messager   r  customers:customer_detailr  r   r  r  SMS sent successfully to .Failed to send SMS. Please check SMS settings.)
get_objectr  r  rs  r  r   r  r   r  r  r  r  r   r  rT   r  r   rG   )rI   rJ   rK   rL   r  r  r  r  rM   rO   rP   r  X  s&   

zCustomerDetailView.post)ri  rj  rk  r!   r  r  r  
slug_fieldslug_url_kwargr~  r   r  rl  rO   rO   rM   rP   r  )  s    r  c                       s8   e Zd ZeZeZdZedZ	dd Z
 fddZ  ZS )CustomerCreateViewcustomers/customer_form.htmlr  c                 C      t | jjrdS | jjds| jjdrdS t| jjds&t| jjdr(dS t| jjdrE| jjjrE| jjjjrE| jjjjjdkrEdS dS )	NTcustomers.add_customerry  add_customeradd_customersrQ   r   F	r9   rJ   rT   r}  r>   rV   rQ   r   r   rY   rO   rO   rP   r~  |  $   
zCustomerCreateView.test_funcc                    s   t  |}| j}tj|dd|j |j|jr|jjnd |j	d| j
j| j
jd| j
jddd |jrjt| t|| j
j}|d r\t| j
d	|j d
|d d  |S t| j
d|d   |S t| j
d	|j d |S )NcreatedzCustomer account created: )r  r  is_sub_accountREMOTE_ADDRHTTP_USER_AGENTr   )r   action_typedescription	new_valueperformed_by
ip_address
user_agentr  	Customer z2 created successfully. Trial period started until 	trial_endz%Y-%m-%d %H:%Mz.Customer created but trial activation failed: r   created successfully.)rG   
form_validr  rB   
log_actiondisplay_namer  r  r   r  rJ   rT   METArs  rC   send_welcome_notificationrD   activate_new_customerr   r  r  r'  r  )rI   formresponser   resultrM   rO   rP   r    s:   



zCustomerCreateView.form_valid)ri  rj  rk  r!   r  r&   
form_classr  r   success_urlr~  r  rl  rO   rO   rM   rP   r  v  s    r  c                       s@   e Zd ZeZeZdZdZdZ	dd Z
dd Z fddZ  ZS )	CustomerUpdateViewr  r  c                 C   r  )	NTzcustomers.change_customerry  change_customerchange_customersrQ   r   Fr  rY   rO   rO   rP   r~    r  zCustomerUpdateView.test_funcc                 C   s   t dd| jjidS )Nr  r  )rL   )r   r  r  rY   rO   rO   rP   get_success_url  rv  z"CustomerUpdateView.get_success_urlc                    s&   t | jd|jj d t |S )Nr  z has been updated successfully.)r   r  rJ   instancer   rG   r  )rI   r   rM   rO   rP   r    s   zCustomerUpdateView.form_valid)ri  rj  rk  r!   r  r&   r  r  r  r  r~  r  r  rl  rO   rO   rM   rP   r    s    r  c                       s4   e Zd ZeZdZedZdd Z fddZ	  Z
S )CustomerDeleteViewz&customers/customer_confirm_delete.htmlr  c                 C   sn   t | jjrdS | jjdst| jjdrdS t| jjdr5| jjjr5| jjjjr5| jjjjjdkr5dS dS )NTr  r  rQ   r   Fr  rY   rO   rO   rP   r~    s   
zCustomerDeleteView.test_funcc                    s8   |   }t|d|j d t j|g|R i |S )Nr  z has been deleted successfully.)r  r   r  r   rG   delete)rI   rJ   rK   rL   r   rM   rO   rP   r    s   zCustomerDeleteView.delete)ri  rj  rk  r!   r  r  r   r  r~  r  rl  rO   rO   rM   rP   r
    s    r
  c                   @       e Zd ZeZdZdZdd ZdS )ServiceListViewz!customers/service_management.htmlr
  c                 C      t | jjS rF   r9   rJ   rT   rY   rO   rO   rP   r~       zServiceListView.test_funcN)ri  rj  rk  r"   r  r  r  r~  rO   rO   rO   rP   r    
    r  c                   @   (   e Zd ZeZeZdZedZ	dd Z
dS )ServiceCreateViewcustomers/package_form.htmlcustomers:service_listc                 C   r  rF   r  rY   rO   rO   rP   r~    r  zServiceCreateView.test_funcNri  rj  rk  r"   r  r'   r  r  r   r  r~  rO   rO   rO   rP   r        r  c                   @   r  )ServiceUpdateViewr  r  c                 C   r  rF   r  rY   rO   rO   rP   r~  
  r  zServiceUpdateView.test_funcNr  rO   rO   rO   rP   r    r  r  c                   @   $   e Zd ZeZdZedZdd ZdS )ServiceDeleteViewz%customers/service_confirm_delete.htmlr  c                 C   r  rF   r  rY   rO   rO   rP   r~    r  zServiceDeleteView.test_funcN)	ri  rj  rk  r"   r  r  r   r  r~  rO   rO   rO   rP   r    
    r  c                   @   r  )CustomerTagListViewzcustomers/tag_list.htmlr  c                 C   r  rF   r  rY   rO   rO   rP   r~    r  zCustomerTagListView.test_funcN)ri  rj  rk  r#   r  r  r  r~  rO   rO   rO   rP   r    r  r  c                   @   r  )CustomerTagCreateViewcustomers/tag_form.htmlcustomers:tag_listc                 C   r  rF   r  rY   rO   rO   rP   r~  $  r  zCustomerTagCreateView.test_funcNri  rj  rk  r#   r  r(   r  r  r   r  r~  rO   rO   rO   rP   r    r  r  c                   @   r  )CustomerTagUpdateViewr  r  c                 C   r  rF   r  rY   rO   rO   rP   r~  -  r  zCustomerTagUpdateView.test_funcNr   rO   rO   rO   rP   r!  '  r  r!  c                   @   r  )CustomerTagDeleteViewz!customers/tag_confirm_delete.htmlr  c                 C   r  rF   r  rY   rO   rO   rP   r~  5  r  zCustomerTagDeleteView.test_funcN)	ri  rj  rk  r#   r  r  r   r  r~  rO   rO   rO   rP   r"  0  r  r"  c                 C   s   t t|d}tjj|dt tjdd id\}}|s6|jr6t	
 |_t tjdd |_d|_|  t| d|j  td|jd	S )
Nr  
expires_atr   r   )r   defaultsFzInvitation sent to r  r  )r   r!   r$   r   get_or_creater   r  r   
is_expireduuiduuid4tokenr#  is_usedsaver   r  r   r   r  )rJ   r  r   
invitationr  rO   rO   rP   send_customer_invitation9  s   


r-  c                 C   s6   t t|d}|jst| d tdS t| dd|iS )N)r)  z5This invitation has expired or has already been used.accounts:loginzcustomers/account_setup.htmlr,  )r   r$   is_validr   r  r   r   )rJ   r)  r,  rO   rO   rP   customer_account_setupO  s
   r0  c                 C   s   t t|d}|jst| d|j d td|jdS d| jd< | jj	| jd< t
| jdd	| jd
< ddlm} |jj| jd| jdd| jdddd |j|jj	dd ddlm} || |jdd t| d|j d tdS )z9Allow staff to view the system as a customer would see itr  r  z" does not have a user account yet.r  Timpersonating_customeroriginal_user_idroleadminoriginal_user_roler   UserActivityLogcustomer_impersonation_startr  r   r  N  )impersonated_customer_idimpersonated_user_idrT   actionr  r  additional_datalogin)django.contrib.auth.backends.ModelBackendbackendz"You are now viewing the system as zC. Use the "Stop Impersonation" button to return to your admin view.customers:dashboard)r   r!   rT   r   r  r   r   r  sessionr  getattraccounts.modelsr7  r   creater  rs  django.contrib.authr@  info)rJ   r  r   r7  r@  rO   rO   rP   view_as_customerY  s*   
rK  c              
   C   s<  | j dst| d tdS | j d}|s"t| d tdS t }z	|jj|d}W n |jyB   t| d td Y S w d	d
lm	} |jj
| jd| jdd| jdddd |t| jdrpt| jdi dnddd | j d= | j d= d| j v r| j d= d	dlm} || |dd t| d tdS )z?Stop impersonating a customer and return to original admin userr1  z/You are not currently impersonating a customer.rD  r2  z%Unable to find original user session.r.  r  zOriginal user no longer exists.r   r6  customer_impersonation_endr  r   r  Nr9  rS   r  )returning_to_user_idr:  r<  r5  r?  rA  rB  zLYou have stopped impersonating the customer and returned to your admin view.r  )rE  rs  r   r  r   r,   r   r  rG  r7  rH  rT   r  rV   rF  rI  r@  r  )rJ   r2  Useroriginal_userr7  r@  rO   rO   rP   stop_customer_impersonation}  s@   "
rP  c              	   C   s   t t|d}| jdkr^t| j}| r]|jd }|jd }|jd }|j}|dv r2| j|7  _n| j|8  _|  t	j
j||||||j| jd t| d|j  td	|jdS nt }t| d
||t	j
j|dd d dS )Nr  r  transaction_typer   r  )creditrefund)r   rQ  r   r  balance_beforebalance_afterprocessed_byz/Balance updated successfully. New balance: KES r  zcustomers/manage_balance.htmlr  r   )r   r   balance_history)r   r!   methodr)   r  r/  cleaned_datar   r+  r%   r   rH  rT   r   r  r   r  r   r   )rJ   r  r   r   rQ  r   r  old_balancerO   rO   rP   manage_customer_balance  s<   





r[  c              
   C   s\  t t|d}| jdkrt| j}| r|jd }|jd pd}|jd }ddd	}|d
kr8t|||| j	}n.|dkrDt
|| j	}n"|dkrQt||| j	}n|dkr]t|| j	}n	|dkrft|}tj||d| d| | j	| jd| jddd |d rt| d|  nt| d|d   td|jdS nt }t| d||dS )zManage customer service statusr  r  r=  reasonzManual actionoverride_dateFzUnknown action)r  r  suspend	reconnect
disconnectstart_trialactivate_servicezService action: z - r  r  r   )r   r  r  r  r  r  r  z'Service action completed successfully: zService action failed: r  r  zcustomers/manage_service.html)r   r   )r   r!   rX  r*   r  r/  rY  rD   suspend_servicerT   reconnect_servicedisconnect_servicer  activate_paid_servicerB   r  r  rs  r   r  r  r   r  r   )rJ   r  r   r   r=  r\  r]  r  rO   rO   rP   manage_customer_service  sL   







	%rg  c                 C   s   t t|d}|jrt| d td|jdS | jdkrOt| j	|d}|
 rN| }tj|dd|j d|ji| jd	 t| d
|j d td|jdS nt|d}t| d||dS )z%Create a sub-account under a customerr  z4Cannot create sub-accounts under another sub-accountr  r  )parent_customersub_account_createdzSub-account created: sub_account_id)r   r  r  r  r  zSub-account r  zcustomers/sub_account_form.html)rh  r   )r   r!   r  r   r  r   r  rX  r+   r  r/  r+  rB   r  rT   r  r   )rJ   r  rh  r   sub_accountrO   rO   rP   create_sub_account  s.   


rl  c                 C   sH   t t|d}t|}t|d}| jd}||}t| d||dS )zView customer action logr  2   pagezcustomers/action_log.html)r   page_obj)	r   r!   rB   get_customer_timeliner-   rr  rs  get_pager   )rJ   r  r   action_logs	paginatorpage_numberro  rO   rO   rP   customer_action_log0  s   


ru  c                 C   s   t t|d}t| jst| jdr| jj|kstddiddS |j|jt	|j
|j|jr/|jnd|jr8|j nd|jt	|j|j|jrH|jjnd|  d	}t|S )
z)API endpoint for real-time service statusr  rS   r  zPermission denied  r   r   N)r  re   r   is_trial_activetrial_remaining_hoursservice_expires_atcan_auto_renewr   r  rh  sub_accounts_count)r   r!   r9   rT   rV   rS   r   r  re   r(  r   rw  rx  ry  	isoformatrz  r   r  rh  get_all_sub_accountsr   )rJ   r  r   status_inforO   rO   rP   customer_service_status_apiA  s&   


r  r{  c                 C   s   t j }t| dd|iS )Nrn  ro  )r!   r   r  r   )rJ   ro  rO   rO   rP   customer_list]  s   
r  c                 C   s   t t|d}t| dd|iS )N)pkr  r   )r   r!   r   )rJ   r  r   rO   rO   rP   customer_detailb  s   r  r  c                 C   s
   t | dS )Nr  )r   )rJ   rO   rO   rP   customer_addg  s   
r  c                    s   t  t fdd}|S )z?Decorator to ensure customers can only access their own objectsc                    s2   t | jdr
| jjstd | g|R i |S )NrS   zCustomer access required)rV   rT   rS   r@   )rJ   rK   rL   	view_funcrO   rP   _wrapped_viewm  s   z+customer_owns_object.<locals>._wrapped_view)rA   r   )r  r  rO   r  rP   customer_owns_objectk  s   r  c                 C   sZ  t dd}d|d< t|}|g d tjd }| j	d}|rK|
t|dt|d	B t|d
B t|dB t|dB t|dB t|dB }| j	d}|rY|j
|d}| j	d}|dkrj|j
dd}n
|dkrt|j
dd}|D ]4}||j|j|j|j|j|j|j|j|j|j|j|j|j|jr|jjnd|j|j|j|jdg qv|S )zExport customers to CSVtext/csvcontent_typez$attachment; filename="customers.csv"Content-Disposition)Customer IDCustomer Type	Full NameCompany NameContact Person First NameContact Person Last NameID/PassportKRA PINPhoneEmailGPS LatitudeGPS LongitudePhysical Addressr"   NotesAccount Balance	Is ActivezCreated Dater  r  r  r  r  r  r  r  r  r  r  rm   rR   rd   r  r   z%Y-%m-%d %H:%M:%S) r   csvwriterwriterowr!   r   r[  r  rr  rs  r   r.   r  r  r   company_namecontact_person_first_namecontact_person_last_nameid_passportkra_pinr   emailgps_latitudegps_longitudephysical_addressr  r   notesr   rF  r?  r'  )rJ   r  r  ro  r  r  rm   r   rO   rO   rP   export_customersx  sh   




r  c                 C   s   t dd}d|d< t|}|g d |g d |g d |g  |dg |d	g |d
g |dg |dg |dg |dg |dg |dg |S )z)Download CSV template for customer importr  r  z3attachment; filename="customer_import_template.csv"r  )r  r  r  r  r  r  r  r  r  r  r  r  r  r"   r  r  r  )r   r  zJohn Doer   r   r   12345678A001234567P	712345678zjohn@example.com-1.292136.8219z123 Main Street, Nairobir   zExample customer0.00True)r   r  r   zABC Company LtdJaneSmithr   P001234567B	723456789zcontact@abc.comr  r  z456 Business Ave, Nairobir   zCorporate customerr  r  z# INSTRUCTIONS:zG# 1. Customer ID: Leave blank for new customers, will be auto-generatedz5# 2. Customer Type: Use "individual" or "institution"z@# 3. For individuals: Fill Full Name, leave company fields blankzA# 4. For institutions: Fill Company Name and Contact Person nameszS# 5. Phone: Enter 9-digit number (e.g., 712345678), 254 will be added automaticallyzA# 6. Service: Use exact service name as in system, or leave blankz%# 7. Is Active: Use "True" or "False"z3# 8. Delete these instruction rows before importing)r   r  r  r  )rJ   r  r  rO   rO   rP   download_template  s"   

	
	r  c                 C   s  | j dkr	tdS | jd}|st| d tdS |jds+t| d tdS z| 	d}t
t|}t| d}d}d}g }t|d	d
D ]\}}	t|	dk rZqN|	d drbqNz{|	d rn|	d  nd}
|	d  }|dvr|d| d| d |d7 }W qN|	d s|d| d |d7 }W qN|	d s|d| d |d7 }W qNd}|
rz	tjj|
d}W n
 tjy   Y nw d}|	d rztjj|	d d}W n tjy   |d| d|	d  d |d7 }Y W qNw ||	d |	d |	d ||	d |	d rt|	d ntd|	d r"|	d  d knd!d"}|d#krF|	d	 s?|d| d$ |d7 }W qN|	d	 |d%< n0|	d& rU|	d' rU|	d( sd|d| d) |d7 }W qN|	d& |d*< |	d' |d+< |	d( |d,< |	d- r|	d- |d.< |	d/ r|	d/ |d0< |	d1 rz
t|	d1 |d2< W n   Y |	d3 rz
t|	d3 |d4< W n   Y |r| D ]\}}t||| q|  |d7 }ntjjd=i |}|d7 }W qN ty } z|d| d5t|  |d7 }W Y d}~qNd}~ww |s	|rt | d6| d7| d8 |r9| d9}|r.|d:d;!|dd(  7 }t"| | W tdS W tdS  ty^ } zt| d<t|  W Y d}~tdS d}~ww )>zImport customers from CSVr  r  csv_filez#Please select a CSV file to import.z.csvzPlease upload a valid CSV file.zutf-8r   rO  )start   #Nr    )r  r  zRow z: Invalid customer type "r     z: Phone number is required	   z: Email is requiredr     )r   z: Service "z" not foundr      r   r  trueT)r  r   r  r  r  r  r   rF  r  z0: Full name is required for individual customersr   rK     r   zP: Company name and contact person names are required for institutional customersr  r  r  r   r  r   r  r   r     r  z: zImport completed: z customers created, z	 updated.z errors occurred during import.z First 5 errors: z; zError processing CSV file: rO   )#rX  r   FILESrs  r   r  r   endswithreaddecoder  readerioStringIOnext	enumerater   
startswithr  r  r!   r   r  r"   r   loweritemssetattrr+  rH  	Exceptionstrr  joinr  )rJ   r  	file_datacsv_datacreated_countupdated_counterror_counterrorsrow_numrowr  r  r   r  customer_datakeyvaluee	error_msgrO   rO   rP   import_customers  s   








	 r  c              
   C   s$  | j dkr	tdS | jd}| jdd }|r|s&t| d tdS z9tjj|d}dd	l	m
} | }|j|j||j| jd
}|rPt| d|j  nt| d W tdS W tdS  tjyr   t| d Y tdS  ty } zt| dt|  W Y d}~tdS d}~ww )zSend SMS to a single customerr  r  r  r  r   z%Customer ID and message are required.r  r   r  r  r  r  zCustomer not found.zError sending SMS: N)rX  r   r  rs  r  r   r  r!   r   r  r  r  r   r  rT   r  r  r  r  r  )rJ   r  r  r   r  r  r  r  rO   rO   rP   send_single_sms  s>   
	 r  c                       s<   e Zd ZdZdd Z fddZ fddZdd	 Z  ZS )
CustomerLoginViewzcustomers/customer_login.htmlc                 C   s   dS )Nz/dashboard/rO   rY   rO   rO   rP   r    s   z!CustomerLoginView.get_success_urlc                    s`   |j dd}| | j}| jjdd}td| d| d|  t| jd t	 
|S )NusernameUnknownr  z-Failed customer login attempt - Customer ID: , IP: z, User-Agent: z2Invalid Customer ID or password. Please try again.)rY  rs  get_client_iprJ   r  login_loggerr  r   r  rG   form_invalid)rI   r   r  r  r  rM   rO   rP   r    s   zCustomerLoginView.form_invalidc                    sf   |  }t|dr|jsttd tdS |jd}| 	| j}t
d| d|  t |S )NrS   z@This login is for customers only. Please use the correct portal.zcustomers:customer_loginr  z)Successful customer login - Customer ID: r  )get_userrV   rS   r   r  rJ   r   rY  rs  r  r  rJ  rG   r  )rI   r   rT   r  r  rM   rO   rP   r    s   zCustomerLoginView.form_validc                 C   2   |j d}|r|dd }|S |j d}|S )zGet client IP addressHTTP_X_FORWARDED_FOR,r   r  r  rs  splitrI   rJ   x_forwarded_foriprO   rO   rP   r    s   zCustomerLoginView.get_client_ip)	ri  rj  rk  r  r  r  r  r  rl  rO   rO   rM   rP   r    s    r  c                   @   s   e Zd ZdZdd ZdS )DashboardMetricsAPIViewz,API endpoint for real-time dashboard metricsc                 C   s  t |jstddiddS tj }tjjdd }ddlm} |jjd	t	
  d
jddd }t|}d}zddlm} |jjddgd }W n	 tyV   Y nw ddlm}	 |jjdt	
 jt	
 jdj|	ddd pud}
t||||t|
t	
  dS )Nr  Unauthorizedrv  r   rR   rd   r   r4   r  r  r  Tr  r]   r|   r}   r   r  rk   rl   rp   rq   rr   )rc   rf   r   r   monthly_revenue	timestamp)r9   rT   r   r!   r   r   r   r   r5   r   r  r`   r  r   r   r   r^   r\  r   r/   r   r   r   r(  r|  )rI   rJ   rc   rf   r5   r  r   r   r^   r/   r  rO   rO   rP   rs    sR   



zDashboardMetricsAPIView.getN)ri  rj  rk  __doc__rs  rO   rO   rO   rP   r    s    r  c                   @   s    e Zd ZdZdd Zdd ZdS )HeartbeatAPIViewz3API endpoint to keep session alive and log activityc                 C   sv   ddl m} |jj|jd| ||jddd d d|jj	dd	 t
d
t  t t|j d  dS )Nr   r6  	heartbeatr  r   r9  T)dashboard_activesession_keyr<  alive)seconds)rm   r  session_expires_at)rG  r7  r   rH  rT   r  r  rs  rE  r  r   r   r  r|  r   get_expiry_age)rI   rJ   r7  rO   rO   rP   r  	  s   
zHeartbeatAPIView.postc                 C   r  )Nr  r  r   r  r  r  rO   rO   rP   r    s   zHeartbeatAPIView.get_client_ipN)ri  rj  rk  r  r  r  rO   rO   rO   rP   r    s    r  )django.shortcutsr   r   r   django.contrib.auth.decoratorsr   r   r   django.contrib.auth.mixinsr   r	   django.contrib.auth.viewsr
   django.contribr   django.views.genericr   r   r   r   r   r   django.urlsr   r   	django.dbr   django.httpr   r   django.viewsr   django.views.decorators.csrfr   django.core.mailr   django.confr   r   r   jsonr'  r  r  django.utilsr   r   r   r   r!   r"   r#   r$   r%   formsr&   r'   r(   r)   r*   r+   rI  r,   django.core.paginatorr-   r   r.   r/   r0   r1   r2   django.appsr3   r   r5   accounts.permissionsr6   r7   r8   r9   r:   r;   r<   r=   r>   r?   django.core.exceptionsr@   	functoolsrA   customers.servicesrB   rC   rD   logging	getLoggerr  rE   rm  r  r  r  r
  r  r  r  r  r  r  r!  r"  r-  r0  rK  rP  r[  rg  rl  ru  r  r  r  r  r  r  r  r  r  r  r  r  rO   rO   rO   rP   <module>   s      4
    , SM@"						
"
.*3!



D/ '/,