
    jOj+9                        d Z ddlmZmZ ddl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 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  ej2                  e      Z e ed            Z ej:                  ddg      d        Zd Z ej:                  ddg      d        Z  ej:                  ddg      d        Z! ej:                  ddg      d        Z"y)uT  
Ads Intelligence — visão read-only de performance de Product Ads por item.

Cruza gasto real (ml_ads_item_daily) com margem do anúncio para classificar
onde o dinheiro está sendo queimado. NÃO altera nada no ML (somente leitura).

Classificações:
  queimando  — gastou e não vendeu NADA via Ads no período
  prejuizo   — ACOS >= margem do produto (cada venda via Ads dá prejuízo)
  atencao    — ACOS >= 70% da margem (lucro via Ads quase zerado)
  saudavel   — ACOS confortável dentro da margem
  escalar    — ACOS <= 40% da margem e vendendo (candidato a aumentar verba)
    )requestjsonifyN)datetime	timedeltatimezone)func)api_bp)SessionLocal)Ad)MlAdsItemDaily)	_classify_suggest_actionAdsDecisionEngineads_write_enabledget_finance_contextmax_acos_for)hoursz/ads-intelligence/overviewGET)methodsc                  h  - t               } 	 t        t        j                  j	                  dd            }t        dt        |d            }t        j                  t              j                         }|t        |      z
  }| j                  t        j                  t        j                   t        j"                        j%                  d      t        j                   t        j&                        j%                  d      t        j                   t        j(                        j%                  d      t        j                   t        j*                        j%                  d	      t        j                   t        j,                        j%                  d
      t        j.                  t        j0                        j%                  d            j3                  t        j                  |k\  t        j                  |k        j5                  t        j                        j7                         }|s!t9        ddg i g d      | j;                          S |D cg c]  }|j                   }}| j                  t<              j3                  t<        j0                  j?                  |            j7                         D ci c]  }|j0                  | }}tA        |       }	tC        |       }
tE        | j                  t        j                  t        j                   t        j,                              j3                  t        j                  j?                  |            j5                  t        j                        j7                               }|	d   r|	d   nd }|	d   r|	d   nd }g }dddddd}i }d}d}d}|D ]>  }tG        |jH                  xs d      }tG        |jJ                  xs d      }t        |j(                  xs d      }t        |j*                  xs d      }t        |jL                  xs d      }|dk  r|dk  r|j	                  |j                        }d }|r!|jN                  tG        |jN                        }|dkD  rtQ        ||z  dz  d      nd }|dkD  rtQ        ||z  d      nd }|dkD  rtQ        ||z  d      nd }|dkD  rtQ        ||z  dz  d      nd }|
jS                  |t        |j	                  |j                        xs d            }tU        ||	|      } tW        ||||| |      }!|j	                  |!d      dz   ||!<   |!dv r||z  }d }"|tQ        ||dz  z  |z
  d      }"d }#|||tQ        ||z
  |z
  d      }#||dkD  r|||z  z  }||z  }|dxx   |z  cc<   |dxx   |z  cc<   |dxx   |z  cc<   |d	xx   |z  cc<   |d
xx   |z  cc<   |jY                  i d|j                  d|r|jZ                  nd d|r|j\                  nd d|r|j^                  nd d|r!|j`                  rtG        |j`                        nd d|r|jb                  nd d |r|jd                  nd dtQ        |d      dtQ        |d      d|d	|d
|dt        |jf                  xs d      d!|d"|d#|d$|||"|!|| |#ti        |!||||t        |jf                  xs d      || ||%
      d&       A dddd'd(d)-|jk                  -fd*+       | j                  t        j                  t        j                   t        j"                        t        j                   t        j&                              j3                  t        j                  |k\  t        j                  |k        j5                  t        j                        jm                  t        j                        j7                         }$|$D %cg c]M  }%|%d   jo                         tQ        tG        |%d   xs d      d      tQ        tG        |%d   xs d      d      d,O }&}%|d   dkD  rtQ        |d   |d   z  dz  d      nd }'|dkD  rtQ        ||z  d      nd }(d })|	d   r|(|'tQ        |(|'z
  |	d   z
  d      })i |	|(|)d-}*t9        |*d.||jo                         |jo                         tQ        |d   d      tQ        |d   d      |'|d   dkD  rtQ        |d   |d   z  d      nd |d   |d	   |d
   tq        |      |tQ        |d      d/
||&d0      | j;                          S c c}w c c}w c c}%w # tr        $ rG}+dd l:},|,jw                          t9        dty        |+      d1      d2fcY d }+~+| j;                          S d }+~+ww xY w# | j;                          w xY w)3Ndays30   x   r   spendads_revenueclicksprintsunitsdays_activeFun   Sem dados em ml_ads_item_daily para o período. Rode o backfill: python -m app.scripts.backfill_ads_item_daily)has_datamessageitemssummarydaily_seriescompletefixed_burden_pcttarget_net_pctg        r   )r   r   r   r    r!   d      )max_acosr)   )	queimandoprejuizog      Y@item_idtitle	thumbnail	permalinkpricestatusskuacosroascpccvr)r-   r)   r*   )margin_percent
ads_profitclassificationlifecycle_stager-   net_margin_pctaction      )r.   r/   atencaosaudavelescalarc                 :    j                  | d   d      | d    fS )Nr=   	   r   )get)xseveritys    P/var/www/hypershopcomercio.com.br/hyper-ai/app/api/endpoints/ads_intelligence.py<lambda>z+ads_intelligence_overview.<locals>.<lambda>   s#    (,,q1A/BA"F7!T     )key)dater   r   )avg_contribution_pctglobal_net_pctT)
total_spendtotal_ads_revenueglobal_acosglobal_roastotal_clickstotal_printstotal_unitsitems_countclass_counts
burn_total)financer#   period_days	date_fromdate_tor&   r%   r'   )r#   error  )=r
   intr   argsrH   maxminr   nowTZ_BRrO   r   queryr   r0   r   sumcostlabelrevenuer   r    units_quantitycountidfiltergroup_byallr   closer   in_r   r   dictfloatr   r   r!   r;   roundinfer_lifecycler   r   appendr1   r2   r3   r4   r5   r6   r"   r   sortorder_by	isoformatlen	Exception	traceback	print_excstr).dbr   today_br
start_dateaggritem_idsaads_mapfinance_ctxengineunits_alltimeburden
target_netr%   totalsrZ   r[   weighted_contribweighted_baser   r   r   r    r!   adr;   r7   r8   r9   r:   stagem_acosr=   r<   r?   dailydr'   rT   avg_contributionrQ   finance_blocker   rJ   s.                                                @rK   ads_intelligence_overviewr   "   s	   	B{7<<##FD121c$n%<<&++-	t 44
 hh""HH^(()//8HH^++,22=AHH^**+11(;HH^**+11(;HH^22399'BJJ~(()//>
 &:-8+
 (>))
*335 	 ! LB J 	
} (++!AII++$&HHRL$7$7		(8K$L$P$P$RSq1447SS *"-"2&RXX""DHH^-J-J$K

&''++H5
6xx@V@V7WX[X[X]_ 5@
4K/0QU6A*6M[!12SW
sa1WXY
 K	A!'',Q'E 23KQ'FQ'F1%EzkQ.QYY'B!Nb''3!&r'8'8!9:E/5,s2A6tD49AI5u,a04D.4qj%*dC4:QJ%,a0DC**2s=3D3DQYY3O3TST/UVE!.+uEF&uk406QN+7+;+;NA+NQR+RL(!::e#
 J)";.52H#IE#QSTU
 "N!n&@TEU!&~'<v'Eq!I)kAo N[$@@ ,7Ou$O=![0!8&8&7Ou$OLL 199RT RR\\T RR\\T	
 B288rxx r"))t rvv ua u[!4 & &  s1==#5A6    s!" s#$ #1("0#(""0).%d*8#amm>Pq:QSW39F9CE1 _K	\ "#aQ[\]

T
U HH^(()HH^++,
 &:-8+
 (>&&
'1D1D(Ecce 	 	  aDNN$51+Q/ qtyq!115
   RXXeQfijQjeF7Of].CCcI1Mpt JWYZIZ5!1M!A1E`dz"'7'CH_"#3k#AKPbDc#cefgN

$4,
 $#--/))+$VG_a8%*6-+@!%D*TZ[bTcfgTguVM%:VG_%LaPmq &x 0 &x 0%g"5z ,#J2 ('
 6 	
} ,SZV  BECF;<cAA

B
 	
sd   H)e e d=Ae 1eT%e *Ae<C0e =e 	f,fff ff f1c                    | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  | j                  | j                  r| j                  j                         nd | j                  r| j                  j                         nd | j                  r| j                  j                         nd | j                  | j                  dS )N)ro   r0   action_coder=   r>   reasonimpactmetrics_snapshotr5   
created_at
decided_atexecuted_atexecution_resultoutcome)ro   r0   r   r=   r>   r   r   r   r5   r   r|   r   r   r   r   )r   s    rK   _rec_to_dictr      s    dd99}}**,,((((..((23,,all,,.D23,,all,,.D45MMq}}..0t..99 rM   z!/ads-intelligence/recommendationsc                     ddl m}  t               }	 t        j                  j                  dd      }|j                  |       }|dk7  r|j                  | j                  |k(        }|j                  | j                  j                               j                  d      j                         }t        |D cg c]  }t        |       c}t!               d      |j#                          S c c}w # t$        $ r2}t        dt'        |      i      d	fcY d }~|j#                          S d }~ww xY w# |j#                          w xY w)
Nr   AdsRecommendationr5   pendingrr   r+   )recommendationsr   r`   ra   )app.models.ads_recommendationr   r
   r   rc   rH   rh   rp   r5   r{   r   desclimitrr   r   r   r   rs   r~   r   )r   r   r5   rh   recsr   r   s          rK   ads_recommendations_listr      s    ?	B!!(I6*+U?LL!2!9!9V!CDE~~/::??ABHHMQQS9=>AQ>!2!4
  	
  ?  /Q()3..

/ 	
sB   B#C. 5C)C. )C. .	D)7D$D)D, $D))D, ,D>z*/ads-intelligence/recommendations/generatePOSTc                     t               } 	 t        |       }|j                  t        t        j
                  j                  dd                  }t        |      | j                          S # t        $ rB}| j                          t        dt        |      i      dfcY d}~| j                          S d}~ww xY w# | j                          w xY w)uL   Gera recomendações sob demanda (o job diário também faz isso às 04:00).r   r   r   r`   ra   N)r
   r   generate_recommendationsrb   r   rc   rH   r   rs   r~   rollbackr   )r   r   r&   r   s       rK   ads_recommendations_generater     s     
B"2&11s7<<;K;KFTX;Y7Z1[w
 	
	  /
Q()3..

	/ 	
s0   AA+ +	B64'B1B6B9 1B66B9 9Cz5/ads-intelligence/recommendations/<int:rec_id>/decidec                    ddl m} t               }	 t        j                  d      xs i }|j                  d      }|dvrt        ddi      d	f|j                          S |j                  |      j                  | 
      j                         }|st        ddi      df|j                          S |j                  dk7  r-t        dd|j                   di      df|j                          S t        j                         |_        d|_        |dk(  r>d|_        |j!                          t        dt#        |      d      |j                          S d|_        |j!                          t%        |      }|j'                  |      \  }}|s	 ddlm}	 |j,                  xs i }
dddd} |	d|j                  |j.                  |j.                         d|
j                  d      xs |j0                  dd  d |j0                   d!|j0                   d"	       t        |j                  ||t#        |      d$      |j                          S # t2        $ r"}t4        j7                  d#|        Y d}~Yd}~ww xY w# t2        $ rB}|j9                          t        dt;        |      i      d%fcY d}~|j                          S d}~ww xY w# |j                          w xY w)&u   
    Decide uma recomendação pendente: {"decision": "accept" | "reject"}.
    accept + ação executável + ADS_WRITE_ENABLED=true -> executa no ML na hora.
    accept com escrita desligada -> fica 'accepted' para execução manual.
    r   r   T)silentdecision)acceptrejectr`   z&decision deve ser 'accept' ou 'reject'i  )ro   u   recomendação não encontradai  r   u   recomendação já está ''i  userr   rejected)r5   recommendationaccepted)send_whatsappPAUSARzREDUZIR/PAUSARzAUMENTAR verba de)pausarreduzir_ou_pausaraumentaru   ✅ Você aceitou:  r1   N<   z (uu   )
Execução automática indisponível — faça no Mercado Ads:
https://ads.mercadolivre.com.br
Busque pelo código z na campanha.u)   WhatsApp do plano B falhou (não-fatal): )r5   executedr$   r   ra   )r   r   r
   r   get_jsonrH   r   rs   rh   	filter_byfirstr5   r   utcnowr   
decided_bycommitr   r   execute_recommendationapp.services.notifierr   r   r   r0   r~   loggerwarningr   r   )rec_idr   r   payloadr   recr   r   r$   r   snapaction_labelsr   s                rK   ads_recommendations_decider     s    @	B5""$/52;;z*//G%MNOQTTb 	
_ hh()33v3>DDFG%EFGLZ 	
Y ::"G'A#**Q%OPQSVVV 	
S "*x#CJIIKjLQTDUVWF 	
C  

		"2&"99#>' P?++1r+3JZh{ |)-*;*;COOS__*])^^_)8S[[#2>?r#++ O+ ,/;;-}	F jj *3/	
  	
  P!J1#NOOP  /
Q()3..

	/ 	
ss   =I2  ?I2 0+I2 ,AI2 8I2 B	I "I2 	I/I*%I2 *I//I2 2	J=;'J8"J=#K  8J==K   K)#__doc__flaskr   r   loggingr   r   r   
sqlalchemyr   app.apir	   app.core.databaser
   app.models.adr   app.models.ml_ads_item_dailyr    app.services.ads_decision_enginer   r   r   r   r   r   	getLogger__name__r   rg   router   r   r   r   r    rM   rK   <module>r      s    #  2 2   *  7 
 
		8	$$% *UG<} =}H& 1E7C D& :VHM N EPVxX= Y=rM   