o
    B_i7d                     @  s.  d dl mZ d dlmZmZmZmZmZ ddlm	Z	m
Z
 ddlmZmZ d dlZd dlZdZd	Zd
ZdZdZdZdZdZdZdZdZdOddZdPddZedZdQd"d#ZdRd%d&Z dRd'd(Z!dSd*d+Z"dTd/d0Z#dUd1d2Z$dVd5d6Z%dWd9d:Z&dXd=d>Z'dd?dYdEdFZ(dZdHdIZ)d[dKdLZ*d\dMdNZ+dS )]    )annotations)AnyDictListTupleOptional   )ZoneOperation	ParamSpec   )requestraw_wrapNcreate_taskupdate_taskmark_task_linkprocessedinsert_task_notesinsert_task_adhoc_materialsupdate_task_substatusupdate_task_project_stageTaskstasksmaterial	materialssOptional[str]returnstrc                 C  s   | d u rdS d|  dS )N z	<![CDATA[z]]> )r   r   r   M/var/www/html/flask_server/apps/aroflo_connector_app/zones/tasks/mutations.py_cdata+   s   r    paramsDict[str, Any]c                 C  s@   |  d}|du r|  d}|du st| stdt|S )u   
    Permite que el CLI use --summary y nosotros lo traduzcamos a taskname.
    También soporta taskname directamente si lo envían.
    tasknameNsummaryu'   taskname/summary no puede estar vacío.)getr   strip
ValueError)r!   r#   r   r   r   _normalize_taskname1   s   

r(   z[,\s]+valuer   
field_name	List[str]c                C  sR  | du rt | dt| tr"dd | D }|s t | d|S t| tr|  }|dr|drzt|}t|trSdd |D }|sPt | d|W S W n/ t	y   |d	d
  }|slt | ddd t
|D }|st | d| Y S w d|v rdd |dD }|st | d|S |r|gS t | d)z
    Acepta:
    - list[str]
    - "id1" (single)
    - "[id1]" (string que parece lista)
    - '["id1","id2"]' (json)
    - "id1,id2" (csv)
    - "[id1,id2]" (brackets sin comillas)
    Nu    no puede ser vacío.c                 S  $   g | ]}t | rt | qS r   r   r&   .0xr   r   r   
<listcomp>N      $ z$_coerce_str_list.<locals>.<listcomp>u    no puede ser una lista vacía.[]c                 S  r,   r   r-   r.   r   r   r   r1   ]   r2   r   c                 S  s(   g | ]}|  r|   d  dqS )"'r&   r/   tr   r   r   r1   f   s   ( ,c                 S  s   g | ]
}|  r|  qS r   r8   r9   r   r   r   r1   m   s    z4 debe ser una lista o un string convertible a lista.)r'   
isinstancelistr   r&   
startswithendswithjsonloads	Exception_LIST_TOKEN_REsplit)r)   r*   outr   parsedinnertokensr   r   r   _coerce_str_list?   sF   




rI   pc                 C  sx  | d }| d }t | }t| }t|dkr|d d }| d}|s)td| d}| d}| d}| d	}| d
}	dg}
|
d| d |
d| d |
d| d |
dt| d |rv|
d| d |r|
dtt| d |r|
dtt| d |r|
dtt| d |	r|
dtt|	 d |
d d|
S ) Nclientid
tasktypeid2   orgidz3orgid es requerido para crear tasks en este tenant.duedatedescriptioncontactnamecontactphonecuston<tasks><task>z<org><orgid>z</orgid></org>z<client><clientid>z</clientid></client>z<tasktype><tasktypeid>z</tasktypeid></tasktype>
<taskname></taskname>z	<duedate>z
</duedate>z<description>z</description>z<contactname>z</contactname>z<contactphone>z</contactphone>z<custon>z	</custon></task></tasks>r   )	r(   r   r&   lenr%   r'   appendr    join)rJ   rK   rL   r#   rN   rO   rP   rQ   rR   rS   partsr   r   r   _build_postxml_createz   s>   







r\   c                 C  s   | d }|  d}|d u r|  d}|  d}|d u r#|d u r#tddd| dg}|d urFt| s9td	|d
tt| d |d urat| sTtd|dtt| d |d d|S )Ntaskidr#   r$   statusz@Debes enviar al menos taskname/summary o status para actualizar.rT   <taskid>	</taskid>u2   taskname/summary no puede ser vacío si se envía.rU   rV   u(   status no puede ser vacío si se envía.z<status>z	</status>rW   r   )r%   r'   r   r&   rY   r    rZ   )rJ   r]   r#   r^   r[   r   r   r   _build_postxml_update   s$   




ra   taskidsc                 C  sB   | st ddg}| D ]}|d| d q|d d|S )Nu   taskids no puede estar vacío.z<tasks>z<task><taskid>z3</taskid><linkprocessed>true</linkprocessed></task>z</tasks>r   r'   rY   rZ   )rb   r[   tidr   r   r   _build_postxml_linkprocessed   s   

re   r]   notesList[Dict[str, Any]]c                 C  s   |st dd|  dg}|D ]U}|d}|rt| s"t d|d}|dd}|d	 |d
tt| d |d urP|dtt| d |dt|rYdnd d |d q|d d|S )Nu   notes no puede estar vacío.<tasks><task><taskid>z</taskid><notes>contentzCada note debe tener content.filterstickyFz<note>z	<content>z
</content>z<filter>z	</filter>z<sticky>truefalsez	</sticky>z</note>z</notes></task></tasks>r   )r'   r%   r   r&   rY   r    boolrZ   )r]   rf   r[   nri   fltrk   r   r   r   _build_postxml_notes   s"   




rq   c                 C  s@  |st dd|  dg}|D ]}|d}|rt| s"t d|d |dr;|dtt|d  d	 |d
tt| d |dd urZ|d|d  d |dd url|d|d  d |dd ur~|d|d  d |dd ur|d|d  d |d q|d d|S )Nu    materials no puede estar vacío.rh   z</taskid><materials>itemz Cada material debe incluir item.z
<material>
partnumberz<partnumber>z</partnumber>z<item>z</item>costz<cost>z</cost>sellz<sell>z</sell>dateusedz
<dateused>z</dateused>quantityz
<quantity>z</quantity>z</material>z</materials></task></tasks>r   )r'   r%   r   r&   rY   r    rZ   )r]   r   r[   mrr   r   r   r   _build_postxml_materials   s,   




ry   r^   substatusidc                 C  s   d|  dt | d| dS )Nrh   z</taskid><status>z!</status><substatus><substatusid>z)</substatusid></substatus></task></tasks>)r    )r]   r^   rz   r   r   r   _build_postxml_update_substatus  s   r{   	projectidstageidc                 C  s`   |s|st ddd|  dg}|r|d| d |r&|d| d |d	 d
|S )Nz#Debes enviar projectid y/o stageid.rT   r_   r`   z<project><projectid>z</projectid></project>z<stage><stageid>z</stageid></stage>rW   r   rc   )r]   r|   r}   r[   r   r   r   #_build_postxml_update_project_stage  s   

r~   resprn   c                 C  sz   z2t | trdD ]}| |}t |trd| v r W dS qt | tr-d|  v r0W dS W dS W dS  ty<   Y dS w )zP
    Detecta error de "zone" de forma defensiva, sin asumir formato exacto.
    )statusmessageerrormessagezoneTF)r<   dictr%   r   lowerrB   )r   kvr   r   r   _is_zone_error  s    

r   rZ   clientprimary_zonealternate_zonepostxmlrZ   c                C  s   d|fg}|r| d|f | d|f t| d|}t|r@|r@||kr@d|fg}|r3| d|f | d|f t| d|S |S )z_
    Ejecuta POST y si falla por error de zona, reintenta una sola vez alternando el zone.
    r   rZ   r   POST)rY   r   r   )r   r   r   r   rZ   params_listr   params_list2r   r   r   _post_with_zone_fallback+  s   

r   List[ZoneOperation]c                  C  sj  t tdddddddd d d d d d d d d d dtdddd	td
dddtddddtddddtddddtddddtddddtddddtddddtddddtddddtd ddd!gd"d#d$gd%dd&t td'd(dddddd d d d d)td*ddd+tdddd,tddddtd-ddd.tddddtd ddd!gd"d/d0gd%dd&t td1d2dddddd3td4d5dd6d7did8tddddtd ddd!gd"d9gd:dd&t td;d<dddddd3td*ddd=td>d5dd?d@ddAdBddCdBddDdBdEdFgddGd8tddddtd dddHgd"d:ddIt tdJdKdddddd3td*ddd=tdLd5ddMd@ddNdBddOdBdPdQdBdPdRdBddSdBdPdTdBdUdVgddGd8tddddtd dddHgd"d%ddIt tdWdXdddddd3td*ddd=td-dddYtdZddd[tddddtd dddHgd"d%ddIt td\d]dddddd3td*ddd=td^ddd_td`dddatddddtd dddHgd"d%ddIg} | S )bNzCreate Taskud   Crea una nueva task (POST zone=Tasks|tasks) usando postxml (fallback automático por error de zone).r   writeF)rawdry_runrN   rK   rL   r#   r$   rO   rP   rQ   rR   rS   rN   stringz"OrgID (opcional pero recomendado).rK   TzClientID requerido por AroFlo.rL   zTaskTypeID requerido.r#   zNombre de la task (taskname).r$   zAlias de taskname (para CLI).rO   zFecha vencimiento (YYYY/MM/DD).rP   u   Descripción.rQ   zNombre contacto.rR   zTel contacto.rS   u   Campo custon (según doc).r   booleanz<Si true, no ejecuta POST; devuelve preview (postxml/params).r   z/Si true, devuelve respuesta cruda + meta debug.r   zCrear task de pruebau    Crear task desde automatizaciónhigh)codelabelrP   http_methodside_effect
idempotentdefault_paramsr!   category	use_cases
risk_levelrequires_confirmationzUpdate TaskzcActualiza una task existente por taskid (POST zone=Tasks|tasks) usando postxml (fallback por zone).)r   r   r]   r#   r$   r^   r]   zTaskID a actualizar.zNuevo taskname.r^   zNuevo status (ej: Pending).zCambiar statuszActualizar nombrezMark Task as linkprocessedua   Marca linkprocessed=true en una o múltiples tasks (POST zone=Tasks|tasks) con fallback por zone.)r   r   rb   arrayz,Lista de taskid a marcar linkprocessed=true.type)items_schemaz+Marcar tasks procesadas por sistema externomediumzInsert Notes to TaskuY   Inserta una o múltiples notas en una task (POST zone=tasks|Tasks) con fallback por zone.zTaskID destino.rf   z+Lista de notas: [{content, filter, sticky}]objectzContenido de la nota.)r   rP   zFiltro (ej: internal only).zSi la nota es sticky.)ri   rj   rk   ri   )r   
propertiesrequiredadditionalPropertiesz
Debug raw.)r   r   rP   r   r   r   r   r!   r   r   r   zInsert AdHoc material to TaskzInserta materiales AdHoc a una task (POST zone=tasks|Tasks join=materials). Nota: GET suele usar join=material, pero para este POST la doc suele pedir join=materials.r   zLista de materials AdHoc.zPart number (opcional).u   Nombre/ítem del material.numberzCosto (opcional).zPrecio de venta (opcional).zFecha uso (YYYY/MM/DD).zCantidad (opcional).)rs   rr   rt   ru   rv   rw   rr   zUpdate Task SubstatuszYActualiza status y substatusid de una task (POST zone=tasks|Tasks) con fallback por zone.zStatus (ej: pending).rz   zSubstatusID.zUpdate Task Project/StagezZActualiza projectid y/o stageid de una task (POST zone=Tasks|tasks) con fallback por zone.r|   z
ProjectID.r}   zStageID.)	r	   	OP_CREATEr
   	OP_UPDATEOP_MARK_LINKPROCESSEDOP_INSERT_NOTESOP_INSERT_MATERIALSOP_UPDATE_SUBSTATUSOP_UPDATE_PROJECT_STAGE)opsr   r   r   get_operationsI  sp  (	!'  Gr   operation_codec                 C  s   | t tttttthv S N)r   r   r   r   r   r   r   )r   r   r   r   supports  s   r   c                 C  s  t |dd}t |dd}dddd}| tkr>t|}dtfd|fg}|r-|||S t|tt|d}|r<t||S |S | tkrft	|}dtfd|fg}|rU|||S t|tt|d}|rdt||S |S | t
krt|ddd}	t|	}dtfd|fg}|r|||S t|tt|d}|rt||S |S | tkr|d }
|d }t|tstdt|
|}dtfd|fg}|r|||S t|tt|d}|rt||S |S | tkr|d }
|d }t|tstdt|
|}dtfdtfd|fg}|r|||tdS t|tt|td}|rt||S |S | tkrGt|d |d |d }dtfd|fg}|r5|||S t|tt|d}|rEt||S |S | tkr|t|d |d|d}dtfd|fg}|rj|||S t|tt|d}|rzt||S |S td|  ) Nr   Fr   r   List[Tuple[str, str]]r   r   rZ   r   r   r"   c                 S  s   dd| ||dS )NTr   )r   r   r!   rZ   r   r   )r   r   rZ   r   r   r   _preview&  s   zexecute.<locals>._previewr   )r   r   r   rb   )r*   r]   rf   znotes debe ser una lista.r   zmaterials debe ser una lista.r   )r   r   r   rZ   r^   rz   r|   r}   u+   [Tasks.mutations] Operación no soportada: r   )r   r   r   r   rZ   r   r   r"   )rn   r%   r   r\   AF_ZONE_TASKS_TITLEr   AF_ZONE_TASKS_LOWERr   r   ra   r   rI   re   r   r<   r=   r'   rq   r   ry   AF_JOIN_MATERIALS_POSTr   r{   r   r~   )r   r   r!   r   r   r   r   r   r   rb   r]   rf   r   r   r   r   execute"  s   	












r   )r   r   r   r   )r!   r"   r   r   )r)   r   r*   r   r   r+   )rJ   r"   r   r   )rb   r+   r   r   )r]   r   rf   rg   r   r   )r]   r   r   rg   r   r   )r]   r   r^   r   rz   r   r   r   )r]   r   r|   r   r}   r   r   r   )r   r   r   rn   )r   r   r   r   r   r   r   r   rZ   r   r   r   )r   r   )r   r   r   rn   )r   r   r   r   r!   r"   r   r   ),
__future__r   typingr   r   r   r   r   baser	   r
   _join_utilsr   r   r@   rer   r   r   r   r   r   r   r   r   AF_JOIN_MATERIALS_GETr   r    r(   compilerC   rI   r\   ra   re   rq   ry   r{   r~   r   r   r   r   r   r   r   r   r   <module>   sF   




;
/








 
K