+
    ?ib                       ^ RI Ht ^ RIt^ RIt^ RIHt ^ RIHtHt ^ RI	t	^ RI
Ht ^ RIHtHtHtHtHtHt ^ RIHt ^ RIHt ^ R	IHt ^ R
IHtHtHt ^ RIHtH t  ^ RI!H"t"H#t# ^ RI$H%t% ^ RI&H't' ^ RI(H)t) ^ RI*H+t+H,t,H-t-H.t. ^ RI/H0t0H1t1 ^ RI2H3t3 ^ RI4H5t5 ^ RI6H7t7 ^ RI8H9t9H:t: ]Pv                  ! ]<4      t=]! RR.R7      t>R R lt?R R lt@]>P                  R^R7      ]! ]4      ]! ]4      3R R  ll4       tB]>P                  R!4      ]! R"4      ]! ]4      ]! ]4      3R# R$ ll4       tC]>P                  R%4      ]! ]4      ]! ]4      3R& R' ll4       tDR# )(    )annotationsN)	timedelta)	AnnotatedAny)parser)	APIRouterDependsFileHTTPExceptionRequest
UploadFile)text)Session)get_settings)get_db_clusterget_db_defaultsession_scope_cluster)AuthUserget_current_user)
has_column	has_table)CampaignCreateBody)campaign_core)audit_trail)check_business_time_windowcheck_remaining_minutes%compute_waiting_time_for_new_campaignfetch_executive_number)campaign_contacts_tablecampaigns_table)parse_csv_content)workbook_bytes_to_contact_rows)dispatch_campaign_to_queue)	format_dtnow_appz/api/campaigns	campaigns)prefixtagsc                    V ^8  d   QhRRRR/# )   vr   returnbool )formats   "0campaign_port/app/controllers/campaign_router.py__annotate__r1   &   s     + + + +    c                    \        V \        4      '       d   V # \        V 4      P                  4       P	                  4       pVR9   # )1)r4   trueonyes)
isinstancer-   strstriplower)r+   ss   & r0   _php_filter_boolr=   &   s8    !TAA***r2   c               8    V ^8  d   QhRRRRRRRRRR	R
R	RRRR/# )r*   business_idintcampaign_idcontact_idsz	list[int]
agent_namer9   callback_urlz
str | Nonerefurldelay_secondsfloatr,   Noner.   )r/   s   "r0   r1   r1   -   sd     I- I-I- I- 	I-
 I- I- I- I- 
I-r2   c                
  "   \        4       p\        \        V 4      4      p\        V4      p	V	R8  d   Rp	V	R8  d   Rp	\        P
                  ! \        P                  ! R4      R7      ;_uu_4       GRj  xL
 p
\        V4       EF#  w  r \        4       ;_uu_ 4       pVP                  \        RV R24      R\        V4      R	\        V4      R
\        V 4      /4      P                  4       P                  4       pV'       g    RRR4       K  \        VP                  R4      ;'       g    R4      P                  4       pV'       gW   VP                  \        RV R24      R\!        4       R\        V4      R	\        V4      R
\        V 4      /4        RRR4       EK  RV RV 2pVP                  \        RV R24      RVR\!        4       R\        V4      R	\        V4      R
\        V 4      /4       RRR4       RXRVRX/pV'       d   VVR&   V'       d   VVR&   V
P#                  VP$                  VR7      G Rj  xL
 p/ p VP'                  4       p\+        V\,        4      '       d   \/        VP                  R4      4      MRpRpRp\+        V\,        4      '       d~   \        VP                  R4      ;'       g    VP                  R4      ;'       g    R4      P                  4       p\        VP                  R4      ;'       g    R4      P                  4       p\        4       ;_uu_ 4       pV'       dd   TP                  \        RV R 24      RT;'       g    TR!T;'       g    R"R\!        4       R\        V4      R	\        V4      R
\        V 4      /4       M\+        V\,        4      '       d   VP                  R#4      MR;'       gA    \+        V\,        4      '       d   VP                  R4      MR;'       g    R$VP0                   2pVP                  \        RV R%24      R!\        V4      R&,          R\!        4       R\        V4      R	\        V4      R
\        V 4      /4       RRR4       T\7        T4      ^,
          8  g   EK  \8        P:                  ! T	4      G Rj  xL
  EK&  	  RRR4      GRj  xL
  R#  ELJ  + '       g   i     EL; i EL  \(         d$    RTP                  ;'       g    RR,          /p ELi ; i  + '       g   i     L; i  \(         d"   p\2        P5                  R'TT4        Rp?LRp?ii ; i L L  + GRj  xL 
 '       g   i     R# ; i5i)(a#  
Fire outbound calls sequentially for the uploaded contacts.

- Reads `number` from `{business_id}_campaign_contacts`
- Calls local MCube proxy endpoint `/api/mcube/outbound-call`
- Sleeps `delay_seconds` between each trigger
- Stores returned `mcube_call_sid` into `call_id` when available
g        g      N@g      4@)timeoutNz&SELECT id, number, name, status FROM `zF` WHERE id = :id AND campaign_id = :cid AND business_id = :bid LIMIT 1idcidbidnumber UPDATE `ze` SET status = 'failed', updated_at = :u WHERE id = :id AND campaign_id = :cid AND business_id = :biducmp_	_contact_zz` SET status = 'calling', call_id = :call_id, updated_at = :u WHERE id = :id AND campaign_id = :cid AND business_id = :bidcall_idtorC   rD   rE   )json_raw:Ni  NokFmcube_call_sidcall_sidstatusz` SET status = 'initiated', call_id = :call_id, dialstatus = :ds, updated_at = :u WHERE id = :id AND campaign_id = :cid AND business_id = :bidds	initiatederrorhttp_zw` SET status = 'failed', dialstatus = :ds, updated_at = :u WHERE id = :id AND campaign_id = :cid AND business_id = :bid:N   Nz%auto-call failed contact_id=%s err=%s)r   r   r@   rG   httpxAsyncClientTimeout	enumerater   executer   mappingsfirstr9   getr:   r%   postmcube_local_outbound_urlrV   	Exceptionr8   dictr-   status_codeloggerr^   lenasynciosleep)r?   rA   rB   rC   rD   rE   rF   settingscontacts_tabledelay_sclienti
contact_iddbrowrN   refidpayloadresp	resp_jsonrX   	mcube_sid
status_txtpreviewes   $$$$$$$                  r0    _auto_call_contacts_after_uploadr   -   s    $ ~H,S-=>N M"G}~  t)<===&{3MAgU*,,**D^DT Uc c s:s;7GPST_P`a hj    -, !!2!8!8b9??AF!

 "*>*: ;_ !_ !')T3z?E3{K[]bdghsdtu !+ -,0 #;-yEEJJ&~&6 7[ [
 &u #j/!3{#3!3{#33 -P & *u+
  .:GN+(.GH%#[[)J)JQX[YY,.	B $		I 3=Y2M2MT)---.SX	
i.. #IMM2B$C$f$fy}}U_G`$f$fdf g m m oI!$Y]]8%<%B%B!C!I!I!KJ*,,

 "*>*: ;_ !_ !*9+=+= $j&?&?K #WY $c*o %s;'7 %s;'7" 8B)T7R7RY]]73X\ : :9CIt9T9T	f 5Z^: :!&t'7'7&89  
 

 "*>*: ;_ !_ !%c'l4&8 #WY $c*o %s;'7 %s;'71 -T 3{#a''mmG,,,Y 4 >== -,,b Z ! B!'$))//r4)@ AIB -,L  UDjRSTTU
 -[ >===sh  A3U-5R?6U-9UTA&STUS+SASTUAS2T
T%T<S
=TSA(T=T1T'T/+T
T
'A#T
0T
<A,T
(T0U
U#U
$	U-U-8U9U-S
TT	8T	TT	T
TTUTU		(U	?UU			UU-U*	U
U*	"U*	$	U-rO   )rm   c          
     ,    V ^8  d   QhRRRRRRRRR	R/# )
r*   requestr   bodyr   user.Annotated[AuthUser, Depends(get_current_user)]
db_defaultr   
db_clusterr.   )r/   s   "r0   r1   r1      sA     S SS
S 9S 	S
 Sr2   c                `   \        VP                  4      pV'       d'   VP                  '       g   \        R RRRRR.//R7      hVP                  p\        V4      p\        WG4      '       g   \        RRRR	R
/R7      h V'       d   VP                  '       d!   \        P                  ! VP                  4      M	\        4       pVP                  f%   VP                  \        4       P                  R7      pV\        RMR7      ,           p	M\        4       pV\        RMR7      ,           p	Rp
VP                  '       d"   \        W6VP                  VP                  4      p
\        VP                   4      pV'       d   ^M^ pVP"                  ;'       g    Rp\%        W6WP&                  4      p/ RVbRVP(                  bRVP*                  bRV'       d   RMRbR^ bRT;'       g    RbRV
bR\-        V4      bR\-        V	4      bRVP/                  R4      bRV	P/                  R4      bRVbRV'       d   ^M^ bR^
bR^bR \        4       bR!\        4       bp\1        WGR"4      '       d   VP                  VR"&   \1        WGR#4      '       d   VP                  VR#&   \1        WGR$4      '       d   WR$&   R%P3                  R& VP5                  4        4       4      pR%P3                  R' VP5                  4        4       4      pVP7                  \9        R(V R)V R*V R+24      V4       \;        VP7                  \9        R,4      4      P=                  4       4      pVP?                  4        VP7                  \9        R-V R.24      R/V/4      PA                  4       PC                  4       pV'       dx    VP7                  \9        R04      R1VRVR\-        V4      R\-        V	4      R2\-        V4      R3\-        \        4       4      R4\-        \        4       4      /4       VP?                  4        VP(                  ;'       g    VPL                  ;'       g    R6p\O        RTR7VPP                  R8TR9R:R;R<R=TR>TR?V'       d   VPS                  R4      MRR@RAT RBV PT                  '       d   V PT                  PV                  MR RC\-        \        4       4       2RDR1TREV'       d   VPS                  R4      MRRV'       d   VPS                  R4      MRRV//
4       V'       d   \Y        V4      M/ pVVRF&   RRGRHVR1VRFV/#   \D         d2   p\F        PI                  R5T4       TPK                  4         Rp?ELCRp?ii ; i  \         d    h \D         d9   p\F        PI                  RIT4       \        RRRJR	\[        T4      RKRL/R7      ThRp?ii ; i)N  messageValidation failederrors
start_timezrequired when scheduledrm   detail  z7Campaign table not found. Please contact administrator.r^   zTable does not existN)tzinfo)daysrO   r?   namedescriptionr[   	scheduledactivetotal_countwaiting_timedidend_time
start_datez%Y-%m-%dend_date
retry_timerun_now
batch_sizebatch_interval
created_at
updated_atbot_idexeuctive_numberretry_logicz, c              3  .   "   T F  pR V R 2x  K  	  R# 5i)`Nr.   .0ks   & r0   	<genexpr>!store_campaign.<locals>.<genexpr>  s     9=a1QCq=s   c              3  ,   "   T F
  pR V 2x  K  	  R# 5i):Nr.   r   s   & r0   r   r     s      @-Q1QC-s   zINSERT INTO `z` (z
) VALUES ()zSELECT LAST_INSERT_ID()SELECT * FROM `"` WHERE campaign_id = :cid LIMIT 1rL   ag  
                        INSERT INTO scheduled_campaigns
                        (campaign_id, business_id, start_time, end_time, execute_at, delay_seconds, status, error_message, created_at, updated_at)
                        VALUES (:campaign_id, :business_id, :start_time, :end_time, :execute_at, 0, 'pending', NULL, :c_at, :u_at)
                        rA   
execute_atc_atu_atz%scheduled_campaigns insert failed: %sUnknownuser_id	user_nameactioncreatemodule	Campaigns
table_nameresource_idresource_namemodifiedz!Campaign created successfully by z from z at detailscampaign_namerK   zCampaign created successfullycampaignzCampaign creation error: %szFailed to create campaignsuccessFi  ).r=   r   r   r   r?   r    r   date_parserparser%   r   replacer   r   r   bot_namecallback_enabledr   r   custom_attempt_valuesr   r   r$   strftimer   joinkeysre   r   r@   
scalar_onecommitrf   rg   rk   rn   r^   rollbackemailr   r   rh   ru   hostrl   r9   )r   r   r   r   r   r   r?   r   startendexecutive_numberr   r   r   waiting_time_valuesinsertcolsplaceholdersrA   r   r   usernameouts   &&&&&                  r0   store_campaignr      s    t||,Gt2H|NgMh>ij
 	

 ""K -JZ,,T/
 	
z:>///K%%doo6wyE||#WY-=-=>)11CIE)11C   5)>)>  ,D,A,AB*Q
&&,,"C[2L2L
"
;"
DII"
 4++"
 Wk(	"

 1"
 /552"
 #"
 )E*"
 	#"
 %..4"
 Z0"
 *"
 Gq"
 ""
 a"
  ')!"
" ')#"
( jh77#}}F8j.@AA)-)>)>F%&jm<<$/=!yy96;;=99yy @&++- @@4-
|3tfJ|n\] ^_agh*,,T2K-LMXXZ[%%?:,.PQRK 
 (*UUW 	
 &"" &{%{$i&6"IcN$i&6	') 4	') 4$ !!#
 9977

77i{4<<X(+j{f!5t?zgnguguguPWP^P^PcPc{}O~  C  DM  NU  NW  DX  CY  Z!;#XX\\&%94hll84dw		
( !)d8nbD	6;+	
 	
7  &DaH##%%&B   2A6:GSVYX]^
 	s   >U U B U 9AU AU F>U A6T  U 'U ;AU AU !"U U  U+&UU UU V-4V-53V((V-z/{campaign_id}/contacts/upload.c               0    V ^8  d   QhRRRRRRRRR	R
RR
/# )r*   rA   r9   r   r   r   r   filer   r   r   r   r.   )r/   s   "r0   r1   r1   Q  sL     c cc
8c c 	c
 c cr2   c                  "   VP                   p\        V4      pVP                  ;'       g    R P                  4       pVP	                  RE4      '       g   \        RRRRRR.//R7      hVP                  \        R	V R
24      RV /4      P                  4       P                  4       p	V	'       g   \        RRR/R7      hVP                  4       G Rj  xL
 p
\        V
4      RF8  d   \        RRR/R7      hVP	                  R4      '       d   \        V
4      pM\        V
P                  RRR7      4      pVP                  R4      '       g!   \        RRVP                  R4      RR/R7      h \         P"                  ! VVV\%        V 4      VR,          4      pVP'                  4        VP                  R4      ;'       g    . pVP                  \        RV R
24      RV /4      P                  4       pV'       d   \%        V^ ,          ;'       g    ^ 4      M^ p\%        VR,          4      pVV,           pVP                  \        RV R24      RVRV /4       VP'                  4        VP                  \        R	V R
24      RV /4      P                  4       P                  4       p	RpV	'       Ed|   \%        V	P                  R4      ;'       g    ^ 4      ^ 8X  EdR   \)        WF4      pVR,          '       g1   \        RRVR,          RRRR R!VP                  R!^ 4      R"VRV/R7      h\+        WF4      pVR,          '       gR   \        RRVR,          RRR#R$R%VP                  R%4      R&VP                  R&4      R'VP                  R'4      R"VRV/R7      hV	P                  R(4      RG9  d<   VP                  \        RV R)24      R*\-        4       RV /4       VP'                  4         \/        V	P                  R+4      ;'       g    R,4      P1                  4       ;'       g    R,pR-pRpRpVP2                  P                  R.4      ;'       g    R P1                  4       ;'       g    RpVP2                  P                  R/4      ;'       g    R P1                  4       ;'       g    RpV Uu. uF2  pVP                  R04      f   K  \%        VP                  R04      4      NK4  	  pp\4        P6                  ! \9        \%        V4      \%        V 4      VVVVVR17      4       RR R2R RR3\        V4       R42R5V/pM&RR RR8V	'       d   V	P                  R94      MR: 2R;R R<R /pRVP                  R4      R"VRVR=VR>VP                  R4      R?VR@V RR RAV/	#  ELu upi   \:         d*   p\<        P?                  R6T4       RRRR7T 2/p Rp?LiRp?ii ; i  \
         d    h \:         d1   p\<        P?                  RBT4       \        RCRRDT 2RR/R7      ThRp?ii ; i5i)HrO   .xlsxr   r   r   r   r   zmust be csv, txt, or xlsxr   r   r   rL     Campaign not foundNzFile too large (max 10MB)zutf-8r   )r   r     r^   FcontactszSELECT total_count FROM `r   rP   z0` SET total_count = :tc WHERE campaign_id = :cidtcr   validinsufficient_minutesT
remain_mincontacts_imported
error_codeBUSINESS_TIME_BLOCKEDbusiness_timecurrent_timecurrent_dayr[   A` SET status = 'active', updated_at = :u WHERE campaign_id = :cidrQ   r   defaultg       @zx-mcube-callback-urlzx-mcube-refurlrK   )r?   rA   rB   rC   rD   rE   rF   startedzCalling started for z contacts (2s delay).rC   zauto-call start failed: %szFailed to start calling: zCampaign scheduled for r   zN/Ar   cron_scheduledprevious_countcontacts_datainserted_contactsrA   call_resultzupload error: %sr   zFailed to upload contacts: )z.csvz.txtr   i   )r   
processing) r?   r    filenamer;   endswithr   re   r   rf   rg   readro   r"   r!   decoderh   r   store_campaign_contactsr@   r   r   r   r%   r9   r:   headersrp   create_taskr   rk   rn   r^   )rA   r   r   r   r   r   r?   r   fnamer   rawparse_resultstore_resultr   currentcurrent_total	new_countupdated_totalr   minutes_checkbtcrC   rF   rD   rE   crB   r   s   &&&&&&                      r0   upload_contactsr  P  s&     ""K -J]]  b'')E>>3442HvHcGd>ef
 	

 !!zl*LMN	 hj  Y@T4UVV		
C
3x""Y@[4\]]~~g5c:(GI)NOI&&Y@P@PQX@Y[dfk4lmm$<<$
 	(,,Z8>>B$$,ZL8Z[\K 
 %' 	 18GAJOO!,Q]34	%	18J<'WXY=%5	
 	%%?:,.PQRK 
 (*UUW 	
 8HLL388q9Q>3JLM ))# #!=#;!5.$m&7&7a&H+Y%}
 
 -ZECw<<# #!3y>!5$&=')A&(?%sww}'=+Y%}	  ||H%-EE""8J</pqr')UK8 !!#![
 !h!7!D!D9EKKMZZQZ
 ## ' 3 34J K Q QrXXZbb^b!//--.>?EE2LLNVVRV9Jf9JAaeeTXk/s155;/9Jf##4$'$4$'$4$/#-%1%&3
 tt!5c+6F5GG\] *	 44S[X\\,5Oaf4ghT $	K |''	2=m\--j9!2;t;

 
	
q v g$  [91=(%<UVWUX:YZ[,   '+!<QC@)US
 	s   CXU>9X>X
 X+AV= =AV= B;V= DV= V 9V *V  V $V =V V V6VAV %V= 2AV= =XV V:V50V= 5V::V= =XX+W>>XXz/{campaign_id}/startc               (    V ^8  d   QhRRRRRRRR/# )r*   rA   r9   r   r   r   r   r   r.   )r/   s   "r0   r1   r1     s6     r rr
8r r 	rr2   c                P   VP                   p\        V4      p\        W54      '       g   \        R RR/R7      hVP	                  \        RV R24      RV /4      P                  4       P                  4       pV'       g   \        R RR/R7      h\        W$4      pVR,          '       gN   \        RRVR,          R	R
RRRVP                  R4      RVP                  R4      RVP                  R4      /R7      h\        W$4      pVR,          '       g-   \        RRVR,          R	R
RRRVP                  R^ 4      /R7      hVP                  R4      R,9  d5   \        RRRVP                  R4       2R	R
RVP                  R4      /R7      h\        V4      p	^ p
\        W94      '       d9   \        VP	                  \        RV	 R24      RV /4      P                  4       4      p
V
^ 8X  dr   VP                  R4      R8X  d\   TP	                  \        RV R24      R\        4       RV /4       VP                  4        ^ RIHp V! V\        V 4      4       RRR	RRR/# VP	                  \        RV R24      R\        4       RV /4       VP                  4         \%        V\        V 4      VR
R
\'        4       P(                  4       VP                  R4      R8X  d   R MR!pRVR	RR"RR#R$/#   \*         d?   p\,        P/                  R%T4       \        R&RR'R	R
R(\1        T4      R#R)T R*2/R7      ThR+p?ii ; i)-r   r   r   r   r   r   rL   r   r   r   Fr   r   r   r   r   r   Tr   r[   pausedzXCampaign can only be started from active, processing, or paused status. Current status: current_statuszSELECT COUNT(*) FROM `zE` WHERE campaign_id = :cid AND (status = 'pending' OR status IS NULL)rP   zD` SET status = 'completed', updated_at = :u WHERE campaign_id = :cidrQ   )delete_queue_for_campaignz6Campaign has no pending contacts. Marked as completed.	completedr   zCampaign resumed successfullyzCampaign started successfullyqueuedmessage_detailzCampaign execution has been queued and will start processing in the background. You can continue using the application while calls are being made.zdispatch error: %sr   zFFailed to queue campaign job. Please ensure queue workers are running.r^   zError: zH. Please check queue configuration and ensure queue workers are running.N)r   r   r  )r?   r    r   r   re   r   rf   rg   r   rh   r   r   r@   r   r%   r   app.utils.rabbitmq_campaignr  r#   r   queue_first_campaignrk   rn   r^   r9   )rA   r   r   r   r?   r   r   r	  r  rs   pendingr  msgr   s   &&&&          r0   start_campaignr    s    ""K -JZ,,Y@T4UVV!!zl*LMN	 hj  Y@T4UVV
$Z
=Cw<<3y>55!9 7sww}5

 
	
 ,JDM!!=35&m//a@	
 	
 ||H%GGuv~  wC  wC  DL  wM  vN  O5 (,,x"8
 	
 -[9NG,,,^,< =A A $ jl
 !|X.(:8J<'klm')UK0	
 	I!+s;/?@Ot
 	
 x
|#def	gi, "N//	
 2:h1G81S-Yxstd  s	
 	
  
)1-c5Q GA3.v"w	
 	
s   AK L%'9L  L%)E
__future__r   rp   loggingdatetimer   typingr   r   ra   dateutilr   r   fastapir   r	   r
   r   r   r   
sqlalchemyr   sqlalchemy.ormr   
app.configr   app.databaser   r   r   app.dependenciesr   r   app.repositories.schema_helperr   r   app.schemas.campaignr   app.servicesr   app.services.audit_logr   app.services.campaign_corer   r   r   r   app.utils.cluster_table_namesr   r    app.utils.csv_parser!   app.utils.excel_parser"   app.utils.queue_dispatchr#   app.utils.timezone_utilr$   r%   	getLogger__name__rn   routerr=   r   ri   r   r  r  r.   r2   r0   <module>r1     s'   "    !  * P P  " # N N 7 @ 3 & .  S 1 @ ? 6			8	$	*+	?+I-X RS!
 ".1!.1S "Sl -.
 Cy!.1!.1c /cL #$ ".1!.1	r %rr2   