
    rkiB                        d dl Z d dlZd dlZd dlmZ d dlZd dlmZmZm	Z	m
Z
mZ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mZmZ d d	lmZmZmZmZmZm Z 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Z+ e       Z,e jZ                  j]                  e jZ                  j_                  e jZ                  j_                  e jZ                  j_                  e0                  dd      Z1 e jd                  e1d       de3de4de4de4dz  de4dz  de5de4dz  de4fdZ6d9de4dede3dz  de4fdZ7e,jq                  d e!       ed"       ed       e	e       e	e      fd#ed$e4d%edz  ded&ef
d'       Z9e,ju                  d ee   !       e	e       e	e      fded&efd(       Z;e,ju                  d)e!       e	e       e	e      fd*e3ded&efd+       Z<e,j{                  d)e!       e	e       e	e      fd*e3d,eded&efd-       Z>e,j                  d)       e	e       e	e      fd*e3ded&efd.       Z@e,ju                  d/ee    !       e	e       e	e      fd*e3ded&efd0       ZAe,ju                  d1e!       e	e      fde4defd2       ZBe,ju                  d3e!       e	e      fde4d4e3defd5       ZCe,jq                  d6e!       e	e      fde4d7edefd8       ZDy):    N)List)	APIRouterBackgroundTasksDependsHTTPException
UploadFileFileForm)Session)settings)get_db)get_current_company)CompanyJobOfferJobApplication)JobOfferResponseJobOfferPublicResponseJobOfferUpdateJobApplicationCreateJobApplicationResponseEnrichedApplicationResponseCandidateInfoMatchScoring)job_offer_service)bot_service)gemini_service)
send_email"HX1ac88f5da34d7e285194c7d80a0db96cuploads
job_offersT)exist_okjob_offer_idcompany_nametitlelocationsalary_rangerequirements	image_urltagc           	      R  K   t        j                  |xs g        d{   }t        d|        h d}	d}
|r&|j                         t	        fd|	D              s|}
|dd}|
r|
|d<   	 t        j                  |       d{   }|r|d	d nd
}|D ]  }|j                  j                  }|s|j                  j                  d	k7  r6|j                  j                  xs g }|rdj                  |      n|r|d   nd}|xs d||xs d|xs d||d| d}	 t        j                  |t        |       d{    t        d| d|          y7 47 # t        $ r}t        d|        Y d}~yd}~ww xY w7 A# t        $ r}t        d| d|        Y d}~	d}~ww xY ww)u   
    Tâche de fond : recherche les profils correspondant au job et envoie
    une notification WhatsApp via le template défini.
    Nu'   Job notification – extracted skills: >      télétravailremoteanywhere	worldwide
distancielteletravailc              3   &   K   | ]  }|v  
 y wN ).0kwlocation_lowers     8/home/www/utuvibe.miabetepe.com/app/job_offers/router.py	<genexpr>z._notify_matching_candidates.<locals>.<genexpr>5   s     CB2'Cs   2   )skillslimitr%   u,   Job notification – search_profiles error:    zjob_default.pngz, r    u   Non préciséz/submit-)1234567)tocontent_sid	variableszJob notification sent to z
 for job #u2   Job notification – send_template_message error (z): )r   extract_skill_keywordsprintloweranyr   search_profiles	Exceptionuserphone_numberidmatch_scorematched_skillsjoinsend_template_messageWHATSAPP_JOB_TEMPLATE_SID)r"   r#   r$   r%   r&   r'   r(   r)   skill_keywords_remote_keywordslocation_for_searchcriteriaprofileseimage_valueprofilephonerR   matched_skillrG   r6   s                       @r7   _notify_matching_candidatesr`   %   s     *@@ASQSTTN	3N3C
DE i!)C2BCC"* !H 2$44X>>
 $-)AB-2CK V))<<??a !,,;;Ar5C		.1_m.YZJ[su ",_0C5!
		V335#  
 -eWJ|nMN9V5 U& ? <QC@A:  	VFugSQRPSTUU	Vs   F'EAF'.E EE BF'E?;E=<E?F'E 	E:"E50F'5E::F'=E??	F$FF'F$$F'db
exclude_idreturnc                     | }d}	 |j                  t              j                  t        j                  | k(        }|r"|j                  t        j                  |k7        }|j                         s| S | d| } |dz  }x)z7Ensure the tag is unique, appending a suffix if needed.   -r<   )queryr   filterr)   rP   first)r)   ra   rb   base_tagcounterrg   s         r7   _ensure_unique_tagrl   h   sw    HG
"))(,,#*=>LL
!:;E{{}J
!G9%1     /)response_model.background_taskspromptimagecurrent_companyc                 :  K   d}d}|r|j                    dt        t        j                                d|j                   }t        j
                  j                  t        |      }t        |d      5 }|j                          d{   }	|j                  |	       ddd       d| }t        j                  ||       d{   }
t        |
d   |      }t        |j                   ||
j                  dd      |
j                  dd      |
j                  d	g       |
j                  d
g       |
j                  d      |
j                  d      |
j                  d      |
      }|j!                  |       |j#                          |j%                  |       | j'                  t(        |j                   |j*                  |j,                  |j.                  |j0                  |j2                  xs g |j4                  |j6                  	       |S 7 # 1 sw Y   qxY w7 Vw)uR   Créer une offre d'emploi via IA à partir d'un prompt et d'une image optionnelle.N_wbz/uploads/job_offers/r)   r$   r=   descriptionr'   responsibilitiesr%   r&   contract_type)

company_idr)   r$   rw   r'   rx   r%   r&   ry   r(   )r"   r#   r$   r%   r&   r'   r(   r)   )rP   inttimefilenameospathrS   
UPLOAD_DIRopenreadwriter   generate_job_offerrl   r   getaddcommitrefreshadd_taskr`   r#   r$   r%   r&   r'   r(   r)   )rp   rq   rr   ra   rs   
image_pathr(   r}   fcontent	generatedr)   	job_offers                r7   create_job_offerr   z   s     JI%(()3tyy{+;*<Aenn=MNWW\\*h7
*d# 	q!JJL(GGGG	 +8*5	 (::6:NNI Yu-r
2C"%%mmGR(MM-4]]>26"'92>z*]]>2mmO4I FF9IIKJJy #\\$11oo##++++1r%%MM  
 O )	 	 Os=   A0H2HHH&HHEHHH	Hc                     | j                  t              j                  t        j                  |j                  k(        j                  t        j                  j                               j                         S )u4   Lister toutes les offres de l'entreprise connectée.)	rg   r   rh   rz   rP   order_by
created_atdescall)ra   rs   s     r7   list_job_offersr      sP     		##'9'99	:	(%%**,	-		rm   z/{offer_id}offer_idc                     |j                  t              j                  t        j                  | k(  t        j                  |j                  k(        j                         }|st        dd      |S )u3   Récupérer le détail d'une offre de l'entreprise.     Offre non trouvéestatus_codedetail)rg   r   rh   rP   rz   ri   r   )r   ra   rs   offers       r7   get_job_offerr      sZ     		x')<)<@R@R)R	S	 

 4HIILrm   update_datac                 j   |j                  t              j                  t        j                  | k(  t        j                  |j                  k(        j                         }|st        dd      |j                  d      }d|v rh|d   j                         j                         }dj                  d |D              }|j                  d	      d
d }t        |||j                        |d<   |j                         D ]  \  }}t        |||        |j                          |j                  |       |S )z&Modifier une offre d'emploi existante.r   r   r   T)exclude_unsetr)   r=   c              3   N   K   | ]  }|j                         s|d k(  r|nd   yw)rf   N)isalnum)r4   cs     r7   r8   z#update_job_offer.<locals>.<genexpr>   s#     I199;!s(a;Is   #%rf   N   )rb   )rg   r   rh   rP   rz   ri   r   
model_dumprJ   striprS   rl   itemssetattrr   r   )	r   r   ra   rs   r   update_dictr)   fieldvalues	            r7   update_job_offerr      s    		x')<)<@R@R)R	S	 

 4HII((t(<K % &&(..0ggISIIiinSb!/REHHME#))+ %uue$% IIKJJuLrm   c           	         |j                  t              j                  t        j                  | k(  t        j                  |j                  k(        j                         }|st        dd      |j                  rt        j                  j                  t        j                  j                  t        j                  j                  t        j                  j                  t                          |j                  j                  d            }t        j                  j                  |      rt        j                  |       |j!                  |       |j#                          ddiS )zSupprimer une offre d'emploi.r   r   r   rn   r   u   Offre supprimée avec succès)rg   r   rh   rP   rz   ri   r   r(   r~   r   rS   dirname__file__lstripexistsremovedeleter   )r   ra   rs   r   img_paths        r7   delete_job_offerr      s     		x')<)<@R@R)R	S	 

 4HII 77<<PX@Y0Z []b]l]l]s]stw]xy77>>(#IIhIIeIIK566rm   z/{offer_id}/applicationsc                 f  K   |j                  t              j                  t        j                  | k(  t        j                  |j                  k(        j                         }|st        dd      |j                  }|sg S |j                  |j                  |j                  xs g |j                  xs g |j                  |j                  d|D cg c]  }|j                  s|j                  s|  }}|D cg c]  }|j                  r|j                  r| }}|r`dt         dt"        dz  fd}t%        j&                  |D cg c]  } ||j(                         c}  d{   }	d	t"        dz  dt"        dz  ffd
}
t%        j&                  |	D cg c]
  } |
|       c}  d{   }t+        ||	|      D ]  \  }}}|rX|j-                  d      |j-                  d      |j-                  d      |j-                  d      |j-                  d      d|_        |sd|j-                  dd      |j-                  dd      |j-                  dg       |j-                  dg       d|_         |j/                          g }|D ]v  }d}|j                  rt1        |j                  j-                  d      |j                  j-                  d      |j                  j-                  d      |j                  j-                  d      |j                  j-                  d            }d}|j                  rwt3        |j                  j-                  dd      |j                  j-                  dd      |j                  j-                  dg       |j                  j-                  dg             }|j5                  t7        |j                  |j8                  |j(                  |j:                  |j<                  ||             y |j?                  d d       |S c c}w c c}w c c}w 7 c c}w 7 w)zELister les candidatures enrichies avec profil candidat et scoring IA.r   r   r   )r$   rw   r'   rx   r%   ry   user_idrc   Nc                   K   t         j                  j                  d       d|  }t        j                         4 d {   }	 |j                  |d       d {   }|j                          |j                         cd d d       d {    S 7 Q7 77 	# t        $ r Y d d d       d {  7   y w xY w# 1 d {  7  sw Y   y xY ww)Nrn   z/api/users/id/g      >@)timeout)	r   BOT_SERVICE_URLrstriphttpxAsyncClientr   raise_for_statusjsonrM   )r   urlclientresponses       r7   fetch_candidatez*list_applications.<locals>.fetch_candidate0  s     --44S9:.	RC((*    f %+ZZTZ%BBH--/#==?	     B 
 !       
      s   =CB CB7BB#B?CBCBC	B4 B7!C,B/-C3B44B77C	=C >C	Cr]   c                 R   K   | sy t        j                  |        d {   S 7 wr2   )r   score_candidate)r]   job_offer_datas    r7   r   z*list_applications.<locals>.score_candidate>  s&     *::>7SSSSs   '%'rO   	full_nameemailcv_datalinkedin_profile)rO   r   r   r   r   score        summaryr=   	strengths
weaknesses)r   r   r   r   )rP   r"   r   status
applied_at	candidatematchingc                 J    | j                   r| j                   j                  S dS )Nr   )r   r   )rs    r7   <lambda>z#list_applications.<locals>.<lambda>{  s    1::qzz// 3 rm   T)keyreverse) rg   r   rh   rP   rz   ri   r   applicationsr$   rw   r'   rx   r%   ry   candidate_datamatching_datar{   dictasynciogatherr   zipr   r   r   r   appendr   r"   r   r   sort)r   ra   rs   r   r   appcached_appsnew_appsr   new_profilesr   r]   new_scoringsscoringresultsr   r   r   s                    @r7   list_applicationsr     s     		x')<)<@R@R)R	S	 

 4HII%%L	 ((**0b!228bNN,,N #/[3#2D2DIZIZ3[K[+_33E3ESM^M^_H_ 	 3 	 4$; 	  %^^6>?sockk*?
 
	T4$; 	T4$; 	T
 %^^6BC7og&C
 

 &)<%N 	!C'$+KK$?!([!9$[[1&{{95(/4F(G&" $[[#6&{{9b9!(["!=")++lB"?	%!	  			 G 	% //33NC,,00=((,,W5**..y9!$!3!3!7!78J!KI #''++GS9))--i<++//R@,,00rB	H 	2vv))KK::~~
 	)> LLFPTLUNe \_ @
 D
sn   CP1P%P2P6P1<PP+P1	P!"P1)P&*/P1P)(P1/P.0A4P1%HP1)P1z/by-tag/{tag}c                 .   |j                  t              j                  t        j                  | k(  t        j                  dk(        j                         }|st        dd      t        j                  |      }|j                  j                  |_
        |S )uA   Récupérer une offre par son tag (utilisé par le bot WhatsApp).Tr      Offre non trouvée ou inactiver   )rg   r   rh   r)   	is_activeri   r   r   model_validatecompanyr#   )r)   ra   r   r   s       r7   get_offer_by_tagr     sv     		#X%7%74%?	@	 

 4TUU%44U;H!MM66HOrm   z#/by-tag/{tag}/application/{user_id}r   c                    |j                  t              j                  t        j                  | k(  t        j                  dk(        j                         }|st        dd      |j                  t              j                  t        j                  |j                  k(  t        j                  |k(        j                         }|st        dd      |S )zPConsulter le statut d'une candidature via le tag de l'offre et l'id utilisateur.Tr   r   r   u0   Aucune candidature trouvée pour cet utilisateur)rg   r   rh   r)   r   ri   r   r   r"   rP   r   )r)   r   ra   r   applications        r7   get_application_statusr     s     		#X%7%74%?	@	 

 4TUU 	 	''5883""g-

 
  4fggrm   z/by-tag/{tag}/applyr   c                 8   |j                  t              j                  t        j                  | k(  t        j                  dk(        j                         }|st        dd      |j                  t              j                  t        j                  |j                  k(  t        j                  |j                  k(        j                         }|rt        dd      t        |j                  |j                        }|j                  |       |j                          |j                  |       |j                  }|r\|j                  rPd|j                    }d	|j"                   d
|j                    d|j                   d}t%        |j                  ||       |S )uR   Soumettre une candidature à une offre via son tag (utilisé par le bot WhatsApp).Tr   r   r   i  u(   Vous avez déjà postulé à cette offre)r"   r   zNouvelle candidature - zBonjour u>   ,

Une nouvelle candidature a été soumise pour votre offre "z" (#u   ).

Connectez-vous à votre espace pour consulter le profil du candidat et son scoring de compatibilité.

Cordialement,
L'équipe TheRecruiter)rg   r   rh   r)   r   ri   r   r   r"   rP   r   r   r   r   r   r   r$   r#   r   )	r)   r   ra   r   existingjob_applicationr   subjectbodys	            r7   apply_to_offerr     sc    		#X%7%74%?	@	 

 4TUU 	 	''5883""k&9&99

 
  4^__$XX##O FF?IIKJJ mmG7==+EKK=9w++, -KKP;;-W\]b]f]f\g h%& 	 	7=='40rm   r2   )Er~   r|   r   typingr   r   fastapir   r   r   r   r   r	   r
   sqlalchemy.ormr   app.core.configr   app.core.databaser   app.auth.dependenciesr   
app.modelsr   r   r   app.job_offers.schemasr   r   r   r   r   r   r   r   app.job_offers.servicer   app.bot_service.servicer   app.search.gemini_servicer   app.core.emailr   rU   routerr   rS   r   r   r   makedirsr{   strlistr`   rl   postr   r   r   r   patchr   r   r   r   r   r   r   r3   rm   r7   <module>r     s   	     ^ ^ ^ " $ $ 5 8 8	 	 	 5 / 4 %@ 	WW\\"''//"''//"''//(:S*TUW`bno
 J &@VC @Vs @VSV @V03d
@VJMPT*@V48@VEH4Z@VVY@VFC W #* PS $ S!12 s)#Dz&/&':;6%66 6 		6
 6 36r C%5 67&/&':;


 8
 M*:; &/&':;  <  m,<= &/&':;	 	 	 >@ } &/&':;777 7 72 &t<W7XY &/&':;nnn n Znj O,BC-4V_ # 7  D 1BXY &/	 	 Z8 "3IJ &//	/%/ 	/ K/rm   