o
    'hP                     @   s  d dl mZ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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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'm(Z(m)Z) d dl*m+Z+ d dl,m-Z- d dl.m/Z/m0Z0m1Z1m2Z2m3Z3 e4e5Z6dd Z7G dd deZ/eee7dd Z8eee7dd Z9eee7dd Z:eed geee7d!d" Z;G d#d$ d$e
eeZ<eee7d%d& Z=eed'd gd(d) Z>eee7d*d+ Z?eee7d,d- Z@eee7d.d/ ZAG d0d1 d1e/e
eZBeee7d2d3 ZCeee7d4d5 ZDeee7d6d7 ZEeee7d8d9 ZFeee7d:d; ZGeee7d<d= ZHeee7d>d? ZIeee7d@dA ZJdS )B    )renderredirectget_object_or_404)messages)login_requireduser_passes_test)LoginRequiredMixinUserPassesTestMixin)ListView
UpdateView)reverse_lazy)	send_mail)settings)JsonResponse)QN)csrf_exempt)require_http_methods)	Paginator)timezone   )SystemSettingsCompanyProfile)CompanyProfileFormTestEmailFormSystemSettingsFormEmailLog)email_service)AdminRequiredMixinhas_admin_accesspermission_requiredhas_permissionget_user_permissionsc                 C   s   t | S )zCheck if user has admin access)r   )user r$   ./var/www/html/optinet_system/settings/views.pyis_admin    s   r&   c                   @   s   e Zd Zdd ZdS )r   c                 C   s
   | j jjS N)requestr#   is_superuserselfr$   r$   r%   	test_func%   s   
zAdminRequiredMixin.test_funcN)__name__
__module____qualname__r,   r$   r$   r$   r%   r   $   s    r   c              
   C   s  | j dkrW| jd}|dkrDg d}|D ]#}| j|d }|r9|dkr+|dks9tjjd|||d	v d
d qt| d td)S |dkr|g d}|D ]#}| j|d }|rq|dv rc|dksqtjjd|||dv d
d qNt| d td)S |dkrg d}|D ]#}| j|d }|r|dkr|dkstjjd|||dv d
d qt| d td)S |dkr| jdd }|r|dkrtjjdd|dd
d t| d td)S |dkrSt	jj
dd\}}| jd d |_| jdd |_| jd!d |_| jd"d |_| jd#d |_| jd$d |_| jd%d |_d&| jv r=| jd& |_d'| jv rI| jd' |_|  t| d( td)S d*d+ }	|	d}
|	d}|	d}|	d,}|	d}|	d-}zt	j }|st	jjd.d/}W n ty } zt	jjd.d/}W Y d0}~nd0}~ww z0d1d2lm} |jjd3d4 |jjd5d4 |jjd6d4 |jjd3t   d7 d8}W n   d0}Y |
|||||||d9}t!| d:|S );zAMain settings dashboard with all configurations and POST handlingPOSTactionsave_email_settings)HOSTPORT	HOST_USERHOST_PASSWORDUSE_TLSUSE_SSLDEFAULT_FROM_EMAILTIMEOUT r6      ••••••••email)r6   )valueis_sensitivecategorykeydefaultsu&   ✅ Email settings saved successfully!save_mpesa_settings)CONSUMER_KEYCONSUMER_SECRETBUSINESS_SHORT_CODEENVIRONMENTPASSKEYCALLBACK_BASE_URL)rF   rI   mpesau'   ✅ M-Pesa settings saved successfully!save_sms_settings)API_KEY
API_SECRET	SENDER_IDAPI_URLrN   sms)rN   u$   ✅ SMS settings saved successfully!save_maps_settingsrM   mapsTu,   ✅ Google Maps settings saved successfully!save_company_settingsr   idcompany_namephoneaddresswebsitetax_idbusiness_registrationcompany_logofavicon)   ✅ Company profile updated successfully!settings:dashboardc                 S   s,   i }t jj| d}|D ]}|j||j< q|S )z;Helper function to get settings for a specific API category)rA   )r   objectsfilterr>   rB   )rA   r   category_settingssettingr$   r$   r%   get_api_settings{   s
   z,settings_dashboard.<locals>.get_api_settingsmikrotikgeneralOptiNet Solutions)rW   Nr   r   sentstatusfailedpending)rk   sent_at__date)
total_senttotal_failedtotal_pending
today_sent)mpesa_settingsemail_settingssms_settingsmikrotik_settingsmaps_settingsgeneral_settingscompany_profileemail_statszsettings/dashboard.html)"methodr0   getstripr   ra   update_or_creater   successr   get_or_createrW   r=   rX   rY   rZ   r[   r\   FILESr]   r^   saver   firstcreate	Exceptionnotifications.modelsr   rb   countr   nowdater   )r(   r1   email_fieldsfieldr>   mpesa_fields
sms_fieldsprofilecreatedre   rs   rt   ru   rv   rw   rx   ry   er   rz   contextr$   r$   r%   settings_dashboard(   s   >1$
	


	
r   c                 C   s~  | j dkr;| jd}|st| d tdS ddddddd	d
dddddd
dddddd
ddd
ddd
ddd
dd
dd
ddd
ddd
dddddd
ddddddd
ddd
ddd
ddd
ddd
ddd
dd d!d
dd"d
dd#d
dd$ddd%d&d'ddid(d
dd)d
dd*d+}||vrt| d,|  tdS d-}i }|d.krd/d0d1d2d3d4d5d6d7d8d9
}||  D ]a\}}|}|d.kr| D ]\}}	|	|kr|} nq| j|d: }
|
sq|
d;krqtj	j
|||
|d< |d= |d>kr|d?v nd
d@dA\}}|s$|
|_|d< |_|d= |_|  |dB7 }qt| |  dC| dD tdS tdS )Ez#Update API settings via modal formsr0   api_typezInvalid API type specified.r`   zM-Pesa Consumer KeyT)descriptionr?   zM-Pesa Consumer SecretzM-Pesa Business Short CodeFzM-Pesa PasskeyzM-Pesa Initiator Namez%M-Pesa Initiator Password (encrypted)z'M-Pesa Environment (sandbox/production)zSTK Push Callback URLzC2B Validation URLzC2B Confirmation URL)
consumer_keyconsumer_secretbusiness_short_codepasskeyinitiator_nameinitiator_passwordenvironmentstk_callback_urlc2b_validation_urlc2b_confirmation_urlz	SMTP Hostz	SMTP PortzSMTP UsernamezSMTP PasswordzUse TLS Encryption)r3   r4   r5   r6   r7   zSMS API KeyzSMS Partner IDzSMS Short CodezSMS API Base URLzSMS API MethodzSMS Phone Parameter NamezSMS Message Parameter Name)rM   
PARTNER_ID
SHORT_CODErP   METHODPHONE_PARAMETERMESSAGE_PARAMETERzMikroTik Router IPzMikroTik API PortzMikroTik UsernamezMikroTik Password)r3   r4   USERNAMEPASSWORDrM   zGoogle Maps API KeyzSystem TimezonezDefault Currency)TIMEZONECURRENCY)rK   r=   rQ   rf   rS   rg   zUnknown API type: r   rK   r   r   r   r   r   r   r   r   r   r   )
rE   rF   BUSINESS_SHORTCODErI   INITIATOR_NAMEINITIATOR_PASSWORDrH   STK_CALLBACK_URLC2B_VALIDATION_URLC2B_CONFIRMATION_URLr;   r<   r   r?   rg   )rE   r3   rM   )r>   r   r?   is_requiredr@   r   z% API settings updated successfully! (z settings saved))r{   r0   r|   r   errorr   itemsr}   r   ra   r   r>   r   r?   r   r   upper)r(   r   api_settings_mapsettings_updatedfield_mappingrB   config
form_fieldform_keydb_keyr>   rd   r   r$   r$   r%   update_api_settings   s   

,



r   c                 C   sn   t jjdd\}}| jdkr*t| j| j|d}| r)|  t	
| d tdS nt|d}t| dd|iS )	zManage company profiler   rU   r0   )instancer_   r`   settings/company_profile.htmlform)r   ra   r   r{   r   r0   r   is_validr   r   r   r   r   )r(   r   r   r   r$   r$   r%   ry   0  s   

ry   r0   c              
   C   s@  zddl }|| j}|d}tj }|stdddW S |dkrL|jrL|jj	r=ddl
}|j	|jj	r=||jj	 d|_|  tdd	d
W S |dkry|jry|jj	rjddl
}|j	|jj	rj||jj	 d|_|  tddd
W S tdd| ddW S  ty } ztdt|dW  Y d}~S d}~ww )zDelete company profile imagesr   N
image_typeFzCompany profile not foundr   r   logoTzLogo deleted successfullyr   messager^   zFavicon deleted successfullyzNo z
 to delete)jsonloadsbodyr|   r   ra   r   r   r]   pathosexistsremover   r^   r   str)r(   r   datar   r   r   r   r$   r$   r%   delete_imageA  s8   

r   c                       s<   e Zd ZeZdZdZdZdd Zdd Z	 fdd	Z
  ZS )
EmailLogListViewsettings/email_logs.html
email_logs   c                 C   s   t | jjS r'   )r   r(   r#   r*   r$   r$   r%   r,   o  s   zEmailLogListView.test_funcc                 C   s   t j d}| jjd}|r|j|d}| jjd}|r&|j|d}| jjd}|rA|t|dt|dB t|d	B }|S )
N-sent_attype
email_typerk   rj   searchrecipient_email__icontainssubject__icontainsrecipient_name__icontains)	r   ra   allorder_byr(   GETr|   rb   r   )r+   querysetr   rk   r   r$   r$   r%   get_querysetr  s"   zEmailLogListView.get_querysetc                    sr   t  jdi |}tj|d< tj|d< | jjdd|d< | jjdd|d< | jjdd|d	< t	 |d
< |S )Nemail_typesstatus_choicesr   r;   selected_typerk   selected_statusr   search_queryrz   r$   )
superget_context_datar   EMAIL_TYPE_CHOICESSTATUS_CHOICESr(   r   r|   r   get_email_statsr+   kwargsr   	__class__r$   r%   r     s   

z!EmailLogListView.get_context_data)r-   r.   r/   r   modeltemplate_namecontext_object_namepaginate_byr,   r   r   __classcell__r$   r$   r   r%   r   i  s    r   c                 C   s   t t|d}t| dd|iS )zView detailed email logrU   zsettings/email_log_detail.html	email_log)r   r   r   )r(   log_idr   r$   r$   r%   email_log_detail  s   r   r   c              
   C   s   | j jr	t| j stdddS z| j jpd}tj|| j d\}}t||r'|nd| dW S  tyU } zt	d|  tdd	t
| dW  Y d
}~S d
}~ww )z0Simple test email endpoint for the navbar buttonFzAccess deniedr   zadmin@optinet.co.kerecipient_emailsent_byzError: r   zError in test email endpoint: zUnexpected error: N)r#   is_authenticatedr   r   r=   r   send_test_emailr   loggerr   r   )r(   r   r   r   r   r$   r$   r%   test_email_endpoint  s(   

r   c              
   C   sT  | j dkrVt| j}| rU|jd }z$t}|j|| jd\}}|r-t	| d| d n	t
| d|  W n! tyT } zt
| dt|  W Y d}~n	d}~ww nt }i }ztjjd	d
d}|j|d< W n tjy|   ttdd|d< Y nw ztjjd	dd}	|	j|d< W n tjy   ttdd|d< Y nw ||d}
t| d|
S )zLTest email configuration by sending a test email using the new email servicer0   
test_emailr   u$   ✅ Test email sent successfully to z2! Please check your inbox (including spam folder).u   ❌ u'   ❌ Error testing email configuration: Nr=   r3   )rA   rB   host
EMAIL_HOSTzNot configuredr5   r#   EMAIL_HOST_USER)r   rt   zsettings/test_email.html)r{   r   r0   r   cleaned_datar   r   r#   r   r   r   r   r   r   ra   r|   r>   DoesNotExistgetattrr   r   )r(   r   r   email_service_instancer   	error_msgr   email_settings_displayhost_settinguser_settingr   r$   r$   r%   test_email_settings  sP   




"r
  c              
   C   s  | j dkr| jdd }| jdd }|r|s%t| d tdS zddlm} | }|d	r9|d
sDt| d tdW S ddl	m
} | }|dr[d|dd  }n|drg|dd }n|dro|}nd|d }|j||| jdd}|rt| d| d n3ddlm}	 |	jj|| jdd }
d}|
r|
jrd|
j }t| d| d| d W tdS W tdS  ty } zt| dt|  W Y d}~tdS d}~ww tdS )z,Test SMS configuration by sending a test SMSr0   
test_phoner;   test_messageu1   ❌ Please provide both phone number and message.r`   r   )get_sms_settingsapi_keyapi_urluG   ❌ SMS API is not properly configured. Please check your SMS settings.)NotificationService0254r   Nz+254+z	Test User)phone_numberr   r   recipient_nameu"   ✅ Test SMS sent successfully to !)SMSLog)recipient_phoner   r   z Error: u   ❌ Failed to send test SMS to .z% Please check your SMS configuration.u%   ❌ Error testing SMS configuration: )r{   r0   r|   r}   r   r   r   settings.utilsr  notifications.servicesr  
startswithlstripsend_smsr#   r   r   r  ra   rb   r   r   error_messager   r   )r(   r  r  r  ru   r  notification_serviceformatted_phoner   r  last_sms_logerror_detailr   r$   r$   r%   test_sms  sn   







 r$  c              
   C   s|  | j dkrztjjddid\}}| jdd |_| jdd |_| jdd |_	| jdd |_
| jd	d |_| jd
d |_| jdd |_| jdd|_| jdd|_d| jv rr| jd |_d| jv r}| jd |_|jst| d tdW S |  t| d W tdS  ty } zt| dt|  W Y d}~tdS d}~ww tdS )z,Update organization/company profile settingsr0   rW   rh   rC   r;   r\   r[   rX   r=   rZ   rY   default_currencyKESr   zAfrica/Nairobir]   r^   zCompany name is required.r`   z+Organization settings updated successfully!z&Error updating organization settings: N)r{   r   ra   r   r0   r|   r}   rW   r\   r[   rX   r=   rZ   rY   r&  r   r   r]   r^   r   r   r   r   r   r   r   )r(   ry   r   r   r$   r$   r%   update_organization8  s<   




 r(  c                       sF   e Zd ZeZeZdZedZ	d
ddZ
 fddZ fdd	Z  ZS )CompanyProfileViewr   r`   Nc                 C   s   t jjddid\}}|S )NrW   rh   r%  )r   ra   r   )r+   r   r   r   r$   r$   r%   
get_objectj  s   
zCompanyProfileView.get_objectc                    s"   t  jdi |}|  |d< |S )Nr   r$   )r   r   r*  r   r   r$   r%   r   q  s   z#CompanyProfileView.get_context_datac                    s   t | jd t |S )Nz%Company profile updated successfully!)r   r   r(   r   
form_valid)r+   r   r   r$   r%   r+  v  s   zCompanyProfileView.form_validr'   )r-   r.   r/   r   r   r   
form_classr   r   success_urlr*  r   r+  r   r$   r$   r   r%   r)  d  s    
r)  c              
   C   s  | j dkrzddl}|| j}|dd }|dd }|dd }|s2tdd	d
W S |s9| d}|s@| d}td| d|  t	 }|drX|ds`tddd
W S ddl
m} | }|||}	|	ddkrt| d|d d tdd|d |d||dW S |	d|	dd}
d|
v rd}n|
}t| d|  tdd | d
W S  ty } ztd!t|  tdd"t| d
W  Y d}~S d}~ww dS )#zRegister M-Pesa paybill URLsr0   r   Nbase_urlr;   validation_urlconfirmation_urlFzPlease provide a base URL.r   z/payments/paybill-validation/z/payments/paybill-confirmation/z&Registering M-Pesa URLs - Validation: z, Confirmation: r   r   IM-Pesa API is not properly configured. Please check your M-Pesa settings.MpesaServiceResponseCoder  uU   ✅ Paybill URLs registered successfully. Customers can now pay using paybill number z* with their customer ID as account number.Tz6Paybill URLs registered successfully. Paybill Number: )r   r   paybill_numberr/  r0  errorMessageResponseDescriptionUnknown errorzInvalid Access Tokena  Invalid Access Token. This usually means:
1. Your M-Pesa app is not approved for production (if using production environment)
2. Your Consumer Key/Secret are incorrect
3. Your app credentials don't match the selected environment

Please verify your credentials and environment settings.u%   ❌ Failed to register paybill URLs: z!Failed to register paybill URLs: z Error registering paybill URLs: zError registering URLs: )r{   r   r   r   r|   r}   r   printr   get_mpesa_settingspayments.servicesr3  register_c2b_urlsr   r   r   r   r   )r(   r   r   r.  r/  r0  rs   r3  mpesa_serviceresponser  detailed_messager   r$   r$   r%   register_paybill_urlsz  sv   






r@  c           	      C   s  zzddl m} W n ty   tddd Y W S w |j ddd }g }|D ]u}zT||jt	|d	d
|j
r@|j
dnd
|jrJ|jdndt	|ddt	|dd|jr_d|jdnd|jrjd|jdnd|jrud|jdnd|jr{dndd
 W q+ ty } ztd|j dt|  W Y d}~q+d}~ww td|t|dW S  ty } z,ddl}| }tdt|  td|  tddt| dddW  Y d}~S d}~ww )z"Get M-Pesa balance inquiry historyr   MpesaBalanceInquiryFzWMpesaBalanceInquiry model not found. Please ensure payments app is properly configured.r   z-created_atN
   conversation_idzN/Az%Y-%m-%d %H:%M:%Sresult_coderesult_desczKSh z,.2f	completedrm   )
rV   rD  
created_atcompleted_atrE  rF  working_account_fundsutility_account_fundscharges_paid_fundsrk   z!Error processing balance inquiry z: T)r   balance_historyr   zError getting balance history: zFull traceback: i  rj   )payments.modelsrB  ImportErrorr   ra   r   r   appendrV   r  rH  strftimerI  rJ  rK  rL  r   r9  r   len	traceback
format_exc)	r(   rB  balance_inquiriesbalance_datainquiry
item_errorr   rS  error_detailsr$   r$   r%   mpesa_balance_history  s`   



rZ  c           	   
   C   sF  | j dkrzoddlm} | }|dr|ds"tdddW S |dd	 }|dd	 }t|d
k s>t|d
k rFtdddW S ddlm	} | }t
d|dd  | }|rmtdd|dddW S tdddW S  ty } zt
dt|  tddt| dW  Y d}~S d}~ww tdddS )z9Test M-Pesa credentials by attempting to get access tokenr0   r   r   r   r   FzIM-Pesa Consumer Key and Secret are required. Please configure them first.r   r;   rC  zNConsumer Key and Secret appear to be too short. Please check your credentials.r2  z,Testing M-Pesa credentials for environment: r   sandboxTz4M-Pesa credentials are valid! Connection successful.)r   r   r   zPFailed to authenticate with M-Pesa. Please check your credentials and try again.z"Error testing M-Pesa credentials: zError testing credentials: NInvalid request method)r{   settings.modelsr   r:  r|   r   r}   rR  r;  r3  r9  get_access_tokenr   r   )	r(   r   rs   r   r   r3  r=  access_tokenr   r$   r$   r%   test_mpesa_credentials  sT   





ra  c              
   C   s(  | j dkrzddl}|| j}|dd }|dd }|r%|s-tddd	W S zt|}|d
k s:|dkrCtddd	W W S W n tyU   tddd	 Y W S w ddl	m
} | }|drj|dsrtddd	W S d}|jjdd|ddd ddlm}	 |	 }
|
j|tt|dt d dd}|ddkrt| d| d | d! td"d#| d$|d%d&W S |d'|d(d)}t| d*| d+|  tdd,| d	W S  ty } zt| d-t|  tdd.t| d	W  Y d}~S d}~ww tdd/d	S )0z"Test M-Pesa STK push functionalityr0   r   Nr  r;   amountFz,Please provide both phone number and amount.r   r   ip z,Amount must be between KES 1 and KES 70,000.zInvalid amount format.r[  r   r   r1  z3https://system.optinet.co.ke/payments/stk-callback/rK   callback_urlzSTK Push callback URL)r>   r   r@   r2  zTEST-z%Y%m%d%H%M%Sz'Test STK Push from Optinet Global Links)r  rb  account_referencetransaction_descr4  r  u'   ✅ Test STK Push sent successfully to z	 for KES z(. Customer should receive M-Pesa prompt.Tz#Test STK Push sent successfully to z). Check your phone for the M-Pesa prompt.CheckoutRequestID)r   r   checkout_request_idr6  r7  r8  u$   ❌ Failed to send test STK Push to z	. Error: z Failed to send STK Push. Error: u   ❌ Error testing STK Push: zError testing STK Push: r]  )r{   r   r   r   r|   r}   r   float
ValueErrorr^  r   r:  ra   r~   r;  r3  stk_pushintr   r   rQ  r   r   r   r   r   )r(   r   r   r  rb  amount_floatr   rs   rc  r3  r=  r>  r  r   r$   r$   r%   test_stk_push<  s   





rm  c              
   C   s   ddl m} | }| }| }dD ]}||r%dt||  ||< qt|||dd|dd|d	d|d
dddS )z.Health check endpoint for M-Pesa configurationr   )MpesaHealthCheck)r   r   *r   r\  r   r;   r   r   )stk_callbackc2b_validationc2b_confirmation)health_checkeffective_configr   callback_urls)settings.health_checksrn  check_mpesa_settingsget_effective_mpesa_configcopyr|   rR  r   )r(   rn  rs  r   safe_configrB   r$   r$   r%   mpesa_health_check  s"   




r{  c              
   C   s`  | j dkrz|ddlm} | }|dr|ds"tdddW S |d	s/tdd
dW S ddlm} | }| }t	d|  |ddkrl|d}|d}ddl
m} |jj||d}	tdd|ddW S |d|dd}
tdd|
 |dW S  ty } zt	dt|  tddt| dW  Y d}~S d}~ww tdddS ) zCheck M-Pesa account balancer0   r   r[  r   r   FzFM-Pesa is not configured. Please configure your M-Pesa settings first.r   r   z5Business Short Code is required for balance checking.r2  zM-Pesa Balance Response: r4  r  ConversationIDOriginatorConversationIDrA  )rD  originator_conversation_idTzRBalance inquiry initiated successfully. You will receive the results via callback.rm   )r   r   rD  rk   r6  r7  r8  zBalance inquiry failed: )r   r   r>  zError checking M-Pesa balance: zError checking balance: Nr]  )r{   r^  r   r:  r|   r   r;  r3  check_account_balancer9  rN  rB  ra   r   r   r   )r(   r   rs   r3  r=  r>  rD  r~  rB  balance_inquiryr  r   r$   r$   r%   check_mpesa_balance  sd   







r  c              	   C   s   t j d}| jd}|r|j|d}| jd}|r$|j|d}| jd}|r>|t|dt|dB t|d	B }|t jt j	| jdd
| jdd
| jdd
d}t
| d|S )zView email logsr   r   r   rk   rj   r   r   r   r   r;   )r   r   r   r   r   r   r   )r   ra   r   r   r   r|   rb   r   r   r   r   )r(   r   r   rk   r   r   r$   r$   r%   r     s0   r   c                 C   s   t jjddd}| jd}|r|j|d}| jd}|r-|t|dt|dB }|t j| jdd	| jdd	d
}t| d|S )zView password reset email logspassword_resetr   r   rk   rj   r   r   r   r;   )password_reset_logsr   r   r   z!settings/password_reset_logs.html)	r   ra   rb   r   r   r|   r   r   r   )r(   r  rk   r   r   r$   r$   r%   r    s"   r  )Kdjango.shortcutsr   r   r   django.contribr   django.contrib.auth.decoratorsr   r   django.contrib.auth.mixinsr   r	   django.views.genericr
   r   django.urlsr   django.core.mailr   django.confr   django.httpr   django.db.modelsr   r   loggingdjango.views.decorators.csrfr   django.views.decorators.httpr   django.core.paginatorr   django.utilsr   modelsr   r   formsr   r   r   r   r   notifications.email_servicer   accounts.permissionsr   r   r    r!   r"   	getLoggerr-   r   r&   r   r   ry   r   r   r   r   r
  r$  r(  r)  r@  rZ  ra  rm  r{  r  r   r  r$   r$   r$   r%   <module>   s    
 z$+
1H*R37\@!