U
    T•FjâF  ã                   @   sò   d Z ddlZddlZddlmZ ddlmZ dZdZdd„ Z	d	d
„ Z
d4dd„Zd5dd„Zdd„ Zd6dd„Zdd„ Zdd„ Zdd„ ZdZdd„ Zd7dd„Zdd„ Zd d!„ Zd"d#„ Zd$d%„ Zd8d'd(„Zd9d)d*„Zd:d,d-„Zd.d/„ Zd0d1„ Zd2d3„ ZdS );u—  Wrapper isolado da API uazapi (WhatsApp), multi-loja.

PrincÃ­pios:
- O token de envio Ã© POR LOJA (tabela whatsapp_config, por id_cliente), nÃ£o do .env.
- O admintoken (nÃ­vel servidor) vem do .env e Ã© usado sÃ³ para criar/gerenciar instÃ¢ncias.
- Nenhuma funÃ§Ã£o aqui pode quebrar o fluxo do pedido: erros sÃ£o capturados e retornados
  como {"ok": False, "erro": "..."} e registrados em whatsapp_log.
é    N)ÚConfig)Úconectaré   é   c              
   C   s–   d}d}znz.tƒ }|jdd}| d| f¡ | ¡ W W ¢@S  tk
rr } ztd|dd W Y ¢W ¢dS d}~X Y nX W 5 |r„|  ¡  |r|  ¡  X dS )z:Retorna a linha de whatsapp_config da loja (dict) ou None.NT)Ú
dictionaryz;SELECT * FROM whatsapp_config WHERE id_cliente = %s LIMIT 1z[UAZAPI obter_config ERRO]©Úflush)Úcloser   ÚcursorÚexecuteÚfetchoneÚ	ExceptionÚprint)Ú
id_clienteÚconnÚcurÚe© r   ú+/var/www/html/LojaOnline/services/uazapi.pyÚobter_config   s"    þ r   c                 C   sò   d}d}zÊzdtƒ }| ¡ }| d| f¡ | ¡ }|rJ| d|||| f¡ n| d| |||f¡ | ¡  W W ¢hdS  tk
rÎ } zBz|rŽ| ¡  W n tk
r¤   Y nX td|dd W Y ¢W ¢dS d}~X Y nX W 5 |rà|  ¡  |rì|  ¡  X dS )	u3   Upsert do token/nome/url da instÃ¢ncia para a loja.Nz<SELECT id FROM whatsapp_config WHERE id_cliente = %s LIMIT 1zª
                UPDATE whatsapp_config
                   SET instancia_nome = %s, instancia_token = %s, url = %s
                 WHERE id_cliente = %s
                z˜
                INSERT INTO whatsapp_config (id_cliente, instancia_nome, instancia_token, url)
                VALUES (%s, %s, %s, %s)
                Tz[UAZAPI _salvar_instancia ERRO]r   F)	r	   r   r
   r   r   Úcommitr   Úrollbackr   )r   ÚnomeÚtokenÚurlr   r   Úrowr   r   r   r   Ú_salvar_instancia-   sB    þ
ú	
û
 r   c                 C   s2   | r| p
i   d¡nd }|p"tjp"d ¡  d¡}|S )Nr   Ú ú/)Úgetr   Ú	UZAPI_URLÚstripÚrstrip)Úcfgr   r   r   r   Ú	_url_base[   s    r$   c                 C   s4   |p
t | ƒ}|r|pi  d¡nd }|p.tjp.d ¡ S )NÚinstancia_tokenr   )r   r   r   ÚUZAPI_TOKENr!   )r   r#   r   r   r   r   Ú_token_lojaa   s    r'   c                 C   s   d  dd„ t| pdƒD ƒ¡S )Nr   c                 s   s   | ]}|  ¡ r|V  qd S )N)Úisdigit)Ú.0Úchr   r   r   Ú	<genexpr>l   s      z_so_digitos.<locals>.<genexpr>)ÚjoinÚstr)Úvalorr   r   r   Ú_so_digitosk   s    r/   c                 C   sŒ   t | ƒ}|sdS t tjƒpd}t |ƒ}| |¡rHt|ƒt|ƒd krH|S t|ƒdkr\|| S t|ƒdkrx|rx|| | S t|ƒdkrˆ|S dS )uL   Normaliza para DDI+DDD+numero (ex.: 5589999999999). Retorna '' se invÃ¡lido.r   Ú55é
   )r1   é   )r   é	   é   )r/   r   ÚUZAPI_DDI_PADRAOÚ
startswithÚlen)ÚnumeroÚ
ddd_padraoÚdZddiÚdddr   r   r   Únormalizar_telefoneo   s    r<   c                 C   sn   t | tƒsdS dD ]}|  |¡rt| | ƒ  S q|  d¡}t |tƒrjdD ]}| |¡rJt|| ƒ  S qJdS )uO   Procura o token da instÃ¢ncia em formatos comuns de resposta do /instance/init.N)r   ZinstanceTokenZapikeyÚhashÚinstance©Ú
isinstanceÚdictr   r-   )ÚdataÚchaveÚinstr   r   r   Ú_buscar_token_resposta…   s    




rE   c                 C   sª   t | tƒsdS t |  d¡tƒr(|  d¡ni }| d¡p>| d¡}t |tƒrR|rR|S |  d¡}t |tƒrx| d¡rtdS dS t |tƒrŠ|rŠ|S |  d¡}t |tƒr¦|r¦|S dS )zÍExtrai o estado textual (connected/connecting/disconnected).

    O servidor pode devolver o estado como texto em instance.status OU como
    objeto em status={connected: true, ...}. Tratamos os dois.
    Nr>   ÚstatusÚstateÚ	connectedÚdisconnectedr?   )rB   rD   ÚsÚstrG   r   r   r   Ú_buscar_status_resposta”   s    



rL   c                 C   s¦   d}d}t | tƒr”t |  d¡tƒr,|  d¡ni }|  d¡pj|  d¡pj|  d¡pj| d¡pj| d¡pj| d¡}|  d¡p’|  d¡p’| d¡p’| d¡}t| ƒ}|||fS )zGProcura QR (base64) e paircode em formatos comuns do /instance/connect.Nr>   ÚqrcodeZqrCodeÚbase64ÚpaircodeZpairCode)r@   rA   r   rL   )rB   ÚqrrO   rD   rF   r   r   r   Ú_buscar_qr_resposta«   s$    

ÿþýüú(rQ   ziConfigure UZAPI_URL e UZAPI_ADMIN_TOKEN no .env do servidor e reinicie: sudo systemctl restart lojaonlinec              
   C   s:  t ƒ }tjpd ¡ }|s(ddt› dœS |s<ddt› dœS zŠtj|› dd|i|dd	œtd
}t|ƒ}|j	dkr~dddœW S |j
s–dt||ƒdœW S t|ƒ}|s®dddœW S t| |||ƒ d|dœW S  tjk
r  } zdd|› dœ W Y ¢S d}~X Y n6 tk
r4 } zdt|ƒdœ W Y ¢S d}~X Y nX dS )uI   Cria uma instÃ¢ncia no servidor (admintoken) e salva o token para a loja.r   Fõ   UZAPI_URL nÃ£o configurada. ©ÚokÚerrou,   UZAPI_ADMIN_TOKEN nÃ£o configurado no .env. z/instance/initÚnameúapplication/json)Ú
admintokenúContent-Type©ÚjsonÚheadersÚtimeouti­  u1   Limite de instÃ¢ncias atingido no servidor (429).u4   InstÃ¢ncia criada mas token nÃ£o retornado pela API.T)rT   r   õ    Falha de conexÃ£o com a uazapi: N)r$   r   ÚUZAPI_ADMIN_TOKENr!   Ú_UZAPI_ENV_HINTÚrequestsÚpostÚTIMEOUT_INSTANCIAÚ_json_seguroÚstatus_coderT   Ú_erro_respostarE   r   ÚRequestExceptionr   r-   )r   r   r   rX   ÚresprB   r   r   r   r   r   Úcriar_instanciaÆ   s6    ü
$ri   c              
   C   s  t | ƒ}t|ƒ}t| |ƒ}|s.ddt› dœS |s<dddœS zpi }|rRt|ƒ|d< tj|› d||ddœtd	}t|ƒ}|j	sdt
||ƒdœW S t|ƒ\}}	}
d
||	|
dœW S  tjk
rä } zdd|› dœ W Y ¢S d}~X Y n6 tk
r } zdt|ƒdœ W Y ¢S d}~X Y nX dS )u7   Gera o QR code (ou paircode) para a instÃ¢ncia da loja.FrR   rS   u@   Esta loja ainda nÃ£o tem instÃ¢ncia. Crie a instÃ¢ncia primeiro.Úphonez/instance/connectrW   ©r   rY   rZ   T)rT   rM   rO   rF   r^   N)r   r$   r'   r`   r/   ra   rb   rc   rd   rT   rf   rQ   rg   r   r-   )r   rj   r#   r   r   Úbodyrh   rB   rP   rO   rF   r   r   r   r   Úconectar_instanciaå   s4    

ü$rm   c              
   C   sø   t | ƒ}t|ƒ}t| |ƒ}|r"|s2ddt|ƒdœS zRtj|› dd|itd}t|ƒ}|jspdt	||ƒddœW S dt
|ƒp|dddœW S  tjk
r¾ } zdd	|› ddœ W Y ¢S d
}~X Y n6 tk
rò } zdt|ƒddœ W Y ¢S d
}~X Y nX d
S )uB   Consulta o estado da conexÃ£o (connected/connecting/disconnected).TrI   )rT   rF   Úconfiguradoú/instance/statusr   ©r\   r]   F)rT   rU   rF   r^   N)r   r$   r'   Úboolra   r   ÚTIMEOUT_ENVIOrd   rT   rf   rL   rg   r   r-   ©r   r#   r   r   rh   rB   r   r   r   r   Ústatus_instancia  s&    
ý&rt   c                  C   s    t jpd ¡  d¡} t jpd ¡ }d}| r|z8ddlm} || ƒjp^|  dd¡ dd¡ 	d¡d }W n t
k
rz   | }Y nX t| ƒt|ƒtt jp’d ¡ ƒ|dœS )u>   DiagnÃ³stico das variÃ¡veis uazapi no .env (sem expor tokens).r   r   r   )Úurlparsezhttps://zhttp://)Zuzapi_url_okZuzapi_admin_okZuzapi_token_plataforma_okZuzapi_url_host)r   r    r!   r"   r_   Úurllib.parseru   ÚnetlocÚreplaceÚsplitr   rq   r&   )r   ZadminÚhostru   r   r   r   Úservidor_env_status  s    ,
ür{   c               
   C   s  t dƒ} tjpd ¡ }| r|s,dddddœS zbtj| › dd|itd	}t|ƒ}|jsldt	||ƒdd
dœW S t
|ƒpvd ¡ }d
|d
|dkdœW S  tjk
rÊ } zdd|› dd
dœ W Y ¢S d}~X Y n: tk
r } zdt|ƒdd
dœ W Y ¢S d}~X Y nX dS )u3   Estado da instÃ¢ncia central (UZAPI_TOKEN do .env).Nr   FrI   u   Plataforma nÃ£o configurada.)rT   rF   rn   rU   ro   r   rp   T)rT   rU   rF   rn   rH   )rT   rF   rn   rH   r^   )r$   r   r&   r!   ra   r   rr   rd   rT   rf   rL   Úlowerrg   r   r-   )r   r   rh   rB   rK   r   r   r   r   Ústatus_instancia_plataforma.  s.    ýü(r}   c              
   C   sà   t | ƒ}t|ƒ}t| |ƒ}|r"|s,dddœS zDtj|› dd|itd}t|ƒ}|jshdt||ƒdœW S ddiW S  tj	k
r¨ } zdd	|› dœ W Y ¢S d
}~X Y n4 t
k
rÚ } zdt|ƒdœ W Y ¢S d
}~X Y nX d
S )u5   Encerra a sessÃ£o do WhatsApp (mantÃ©m a instÃ¢ncia).Fu   InstÃ¢ncia nÃ£o configurada.rS   z/instance/disconnectr   rp   rT   Tr^   N)r   r$   r'   ra   rb   rc   rd   rT   rf   rg   r   r-   rs   r   r   r   Údesconectar_instanciaJ  s&    

ý
$r~   Úmanualc              
   C   st  t ||ƒ}|s(t| ||ddƒ dddœS t| ƒ}t|ƒ}t| |ƒ}|rJ|sdt| ||ddƒ dddœS zrtj|› d||d	œ|d
dœtd}	t|	ƒ}
|	j	s¾t
|	|
ƒ}t| ||d|ƒ d|dœW S t| ||ddƒ ddiW S  tjk
r& } z.t| ||dd|› ƒ dd|› dœ W Y ¢S d}~X Y nJ tk
rn } z*t| ||dt|ƒƒ dt|ƒdœ W Y ¢S d}~X Y nX dS )uP   Envia texto pela instÃ¢ncia da loja. Nunca lanÃ§a exceÃ§Ã£o; retorna {ok, erro}.rU   õ   telefone invÃ¡lidoFõ   Telefone invÃ¡lido.rS   u   instÃ¢ncia nÃ£o configuradau)   WhatsApp nÃ£o configurado para esta loja.ú
/send/text©ÚnumberÚtextrW   rk   rZ   rT   NTú	conexao: r^   )r<   Ú_logr   r$   r'   ra   rb   rr   rd   rT   rf   rg   r   r-   )r   ÚtelefoneÚmensagemÚeventor9   Útelefone_normr#   r   r   rh   rB   rU   r   r   r   r   Úenviar_textod  s<    



ü

$rŒ   c                    s.   ‡ ‡‡‡‡fdd„}t j|dd}| ¡  |S )uK   Dispara o envio em thread separada para nÃ£o travar a resposta HTTP do PDV.c               
      sL   zt ˆˆˆˆˆ d W n0 tk
rF }  ztd| dd W 5 d } ~ X Y nX d S )N)rŠ   r9   z [UAZAPI enviar_texto_async ERRO]Tr   )rŒ   r   r   )r   ©r9   rŠ   r   r‰   rˆ   r   r   Ú_runŠ  s    z enviar_texto_async.<locals>._runT)ÚtargetÚdaemon)Ú	threadingÚThreadÚstart)r   rˆ   r‰   rŠ   r9   rŽ   Útr   r   r   Úenviar_texto_asyncˆ  s    r•   Ú
plataformac              
   C   s€  t | dƒ}|dk	r|nd}|s8t|| |ddƒ dddœS tdƒ}tjpHd ¡ }|rV|spt|||dd	ƒ dd
dœS zrtj|› d||dœ|ddœtd}t	|ƒ}	|j
sÊt||	ƒ}
t|||d|
ƒ d|
dœW S t|||ddƒ ddiW S  tjk
r2 } z.t|||dd|› ƒ dd|› dœ W Y ¢S d}~X Y nJ tk
rz } z*t|||dt|ƒƒ dt|ƒdœ W Y ¢S d}~X Y nX dS )uE   Envia texto pela instÃ¢ncia central (Config.UZAPI_URL + UZAPI_TOKEN).Nr   rU   r€   Fr   rS   r   u   plataforma nÃ£o configuradau%   WhatsApp plataforma nÃ£o configurado.r‚   rƒ   rW   rk   rZ   rT   Tr†   r^   )r<   r‡   r$   r   r&   r!   ra   rb   rr   rd   rT   rf   rg   r   r-   )rˆ   r‰   rŠ   Úid_cliente_logr‹   Zlog_clienter   r   rh   rB   rU   r   r   r   r   Úenviar_texto_plataforma•  s<    


ü

$r˜   c                 C   s:   z
|   ¡ W S  tk
r4   d| jp$dd d… i Y S X d S )NÚ_rawr   i,  )r[   r   r…   )rh   r   r   r   rd   ¼  s    
rd   c                 C   s¤   t |tƒr˜| d¡p| d¡}t |tƒrF| ¡ rFd| j› d| ¡ › S | d¡}t |tƒrx| ¡ rxd| j› d| ¡ › S | d¡r˜d| j› d|d › S d| j› S )NÚmessagerU   zHTTP z: Úerrorr™   )r@   rA   r   r-   r!   re   )rh   rB   ÚmsgÚerrr   r   r   rf   Ã  s    


rf   c                 C   sø   d }d }zÐzttƒ }| ¡ }| d| t|p*dƒd d… t|p<dƒd d… t|pNdƒd d… |rlt|ƒd d… nd f¡ | ¡  W nV tk
rÔ } z8z|rž| ¡  W n tk
r´   Y nX td|dd	 W 5 d }~X Y nX W 5 |ræ|  ¡  |rò|  ¡  X d S )
Nz‡
            INSERT INTO whatsapp_log (id_cliente, telefone, evento, status, erro)
            VALUES (%s, %s, %s, %s, %s)
            r   é(   é<   r   iô  z[UAZAPI _log ERRO]Tr   )	r	   r   r
   r   r-   r   r   r   r   )r   rˆ   rŠ   rF   rU   r   r   r   r   r   r   r‡   Ð  s.    8ÿû$r‡   )N)N)N)N)r   N)r   N)r–   N)Ú__doc__r‘   ra   Úconfigr   Údatabaser   rr   rc   r   r   r$   r'   r/   r<   rE   rL   rQ   r`   ri   rm   rt   r{   r}   r~   rŒ   r•   r˜   rd   rf   r‡   r   r   r   r   Ú<module>   s:   .



ÿ

$

'