Ë
    ÓüíiVs  ã                  ó°  — d dl mZ d dlZd dlmZ d dlmZ d dlmZm	Z	 d dl
mZ d dlmZmZ d dlmZmZmZ d d	lmZ d d
lmZmZ d dlmZ d dlmZ d dlmZ  G d„ de«      Zd dlm Z  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+m,Z,m-Z-m.Z. ddl/m0Z0 ddl1m2Z2m3Z3m4Z4m5Z5m6Z6 d„ Z7 G d„ dejp                  «      Z9 G d„ d«      Z: G d„ de:ejv                  «      Z< G d„ de:ejv                  «      Z= G d „ d!e:ejv                  «      Z> G d"„ d#e:ejv                  «      Z? G d$„ d%e:ejv                  «      Z@d d&lAmBZBmCZC d d'l
mDZDmEZEmFZF d d(lGmHZH d d)lImJZJ  G d*„ d+eJ«      ZKy),é    )ÚannotationsN)ÚDecimal)Úapps)ÚIntegrityErrorÚtransaction)ÚPrefetch)ÚpermissionsÚviewsets)ÚMultiPartParserÚ
FormParserÚ
JSONParser)Úaction)ÚValidationErrorÚPermissionDenied)ÚOrderingFilter)ÚPageNumberPagination)ÚResponsec                  ó   — e Zd ZdZdZdZdZy)ÚCollectionPaginationé2   Ú	page_sizeéÈ   ÚpageN)Ú__name__Ú
__module__Ú__qualname__r   Úpage_size_query_paramÚmax_page_sizeÚpage_query_param© ó    ú1/var/www/html/acx/collections_management/views.pyr   r      s   „ Ø€IØ'ÐØ€MØÑr!   r   )ÚDjangoFilterBackendé   )ÚCollectionCaseFilter)ÚCollectionCaseÚCollectionActionÚPaymentPromiseÚPaymentÚCollectionEmail)ÚCollectionCaseSerializerÚCollectionActionSerializerÚPaymentPromiseSerializerÚPaymentSerializerÚCollectionEmailSerializer)Ú CollectionCaseTimelineSerializer)Úapply_action_to_caseÚrecompute_case_balancesÚsync_treasury_for_paymentÚsend_acx_emailÚattach_outlook_emlc                óz  — t        | dd «      }|r|S t        | dd «      }|r|j                  sy d }dD ]  }	 t        j                  |d«      }|r nŒ |sy |j
                  j                  d«      j                  |d¬«      j                  d«      j                  «       }|r|j                  S d S # t        $ r Y Œ‡w xY w)NÚtenantÚuser)ÚaccountsÚtenancyÚ
MembershipÚactive)r8   Ústatusz-id)ÚgetattrÚis_authenticatedr   Ú	get_modelÚ	ExceptionÚobjectsÚselect_relatedÚfilterÚorder_byÚfirstr7   )Úrequestr7   r8   r;   Ú	app_labelÚms         r"   Úresolve_tenant_from_requestrJ   /   sÓ   € ä�W˜h¨Ó-€FÙØˆô �7˜F DÓ)€DÙ�t×,Ò,Øð €JØ,ò ˆ	ð	ÜŸ™¨	°<Ó@ˆJÙÙð ðñ Øð 	×Ñß	‰˜Ó	!ß	‰�T (ˆÓ	+ß	‰�%‹ß	‰‹ð ñ ˆ1�8‰8Ð"˜dÐ"øô ò 	Ùð	ús   ¶B.Â.	B:Â9B:c                  ó   — e Zd ZdZd„ Zy)ÚIsTenantMemberu>   
    Placeholder (marchÃ©) : remplace par votre RBAC ACX.
    c                ó\   — t        |j                  xr |j                  j                  «      S ©N)Úboolr8   r?   )ÚselfrG   Úviews      r"   Úhas_permissionzIsTenantMember.has_permissionY   s    € Ü�G—L‘LÒB W§\¡\×%BÑ%BÓCÐCr!   N)r   r   r   Ú__doc__rR   r    r!   r"   rL   rL   U   s   „ ñóDr!   rL   c                  ó"   — e Zd ZdZd„ Zd„ Zd„ Zy)ÚTenantScopedQuerysetMixinz%
    Toujours scoper par tenant.
    c                óJ   — t        | j                  «      }|st        d«      ‚|S )Nz(Tenant context missing for this request.)rJ   rG   r   )rP   r7   s     r"   Ú
get_tenantz$TenantScopedQuerysetMixin.get_tenantf   s$   € Ü,¨T¯\©\Ó:ˆÙÜ"Ð#MÓNÐNØˆr!   c                óF   — | j                  «       }|j                  |¬«      S )N©r7   )rW   rD   )rP   Úqsr7   s      r"   Úfilter_by_tenantz*TenantScopedQuerysetMixin.filter_by_tenantl   s   € Ø—‘Ó"ˆØ�y‰y ˆyÓ'Ð'r!   c                ór   — | j                  «       }|j                  || j                  j                  ¬«       y )N©r7   Ú
created_by)rW   ÚsaverG   r8   )rP   Ú
serializerr7   s      r"   Úperform_createz(TenantScopedQuerysetMixin.perform_createp   s(   € Ø—‘Ó"ˆØ�‰˜v°$·,±,×2CÑ2CˆÕDr!   N)r   r   r   rS   rW   r[   ra   r    r!   r"   rU   rU   a   s   „ ñòò(óEr!   rU   c                  ó–   — e Zd ZeZegZeegZ	e
Zg d¢ZdgZej                  j!                  «       Zd„ Zd„ Z eddgd¬«      dd
„«       Zy	)ÚCollectionCaseViewSet)Ú
created_atÚ
updated_atÚnext_action_dateÚpriorityr=   z-updated_atc                óî   — | j                  t        j                  j                  «       «      }| j                  j
                  j                  d«      }|r |j                  |j                  «       ¬«      }|S )NÚcountry)Údebtor__country__iexact)	r[   r&   rB   ÚallrG   Úquery_paramsÚgetrD   Ústrip)rP   rZ   Úcountry_codes      r"   Úget_querysetz"CollectionCaseViewSet.get_querysetƒ   s\   € Ø×"Ñ"¤>×#9Ñ#9×#=Ñ#=Ó#?Ó@ˆØ—|‘|×0Ñ0×4Ñ4°YÓ?ˆÙØ—‘°<×3EÑ3EÓ3G�ÓHˆBØˆ	r!   c                ó¾  — | j                  «       }| j                  |j                  ¬«      }|j                  d¬«       |j                  }|j                  d«      }|st        ddi«      ‚g d¢}	 t        j                  «       5  t        j                  j                  ||i |D �	ci c]  }	|	|v sŒ|	|j                  |	«      “Œ c}	¥d|j                  i¥¬«      \  }
}d	d	d	«       s„g }|D ]e  }	|	|v sŒ|j                  |	«      €Œt        
|	«      |j                  |	«      k7  sŒ9t        |
|	|j                  |	«      «       |j!                  |	«       Œg |r
j#                  |dgz   ¬«       | j                  
«      j                  }t%        ||rd¬«      S d¬«      S c c}	w # 1 sw Y   ŒÅxY w# t        $ r& t        j                  j                  ||¬
«      }
d}Y Œöw xY w)u®   
        âœ… CrÃ©ation idempotente sur (tenant, reference).
        - si (tenant, reference) existe dÃ©jÃ  => renvoie l'existant (200)
        - sinon => crÃ©e (201)
        )ÚdataT)Úraise_exceptionÚ	referencezreference is required)Ú	portfolioÚdebtorr=   rg   Úassigned_toÚprincipal_amountÚinterest_amountÚpenalty_amountÚfees_amountÚtotal_paid_amountÚdue_dateÚnext_action_typerf   Únotesr^   )r7   rt   ÚdefaultsN)r7   rt   Fre   ©Úupdate_fieldséÉ   r   ©r=   )rW   Úget_serializerrr   Úis_validÚvalidated_datarm   r   r   Úatomicr&   rB   Úget_or_creater8   r   r>   ÚsetattrÚappendr_   r   )rP   rG   ÚargsÚkwargsr7   r`   Úvdrt   Úupdatable_fieldsÚkÚobjÚcreatedÚchangedÚouts                 r"   ÚcreatezCollectionCaseViewSet.createŠ   sÑ  € ð —‘Ó"ˆà×(Ñ(¨g¯l©lÐ(Ó;ˆ
Ø×Ñ¨DÐÔ1Ø×&Ñ&ˆà—F‘F˜;Ó'ˆ	ÙÜ! ;Ð0GÐ"HÓIÐIò
Ðð"	Ü×#Ñ#Ó%ñ Ü-×5Ñ5×CÑCØ!Ø'ðØ1AÖM¨AÀQÈ"ÂW˜1˜bŸf™f Q›i™<ÒMðà$ g§l¡lñð  Dó  ‘��W÷ñ ØˆGØ%ò *�Ø˜’7˜rŸv™v a›yÑ4Ü˜s A“¨"¯&©&°«)Ó3Ü  Q¨¯©¨q«	Ô2ØŸ™ qÕ)ð	*ñ
 Ø—‘ w°,°Ñ'?�Ô@à×!Ñ! #Ó&×+Ñ+ˆÜ˜©7 CÔ<Ð<¸Ô<Ð<ùò' N÷ð ûô ò 	Ü ×(Ñ(×,Ñ,°FÀiÐ,ÓPˆCØŠGð	úsB   Á0F- Â!F!Â%	FÂ/FÃF!ÃF- ÆF!Æ!F*Æ&F- Æ-,GÇGTrm   Útimeline)ÚdetailÚmethodsÚurl_pathNc                ó8  — |j                   j                  d«      }	 |rt        |«      nd}| j	                  «       }t
        j                  j                  ||¬«      j                  ddd«      j                  t        dt        j                  j                  |¬«      j                  d	«      j                  d
«      d¬«      t        dt        j                  j                  |¬«      j                  d«      j                  d
«      d¬«      t        dt        j                  j                  |¬«      j                  d«      j                  d
«      d¬«      «      }|j                  «       }|st!        ddid¬«      S t#        t%        |dg «      «      d| }t#        t%        |dg «      «      }t#        t%        |dg «      «      }	t'        d„ |	D «       t)        d«      «      }
|j*                  |
z
  }|t)        d«      k  rt)        d«      }||||	t-        |j*                  «      t-        |
«      t-        |«      t-        |j.                  «      j1                  «       |j2                  |j4                  dœdœ}t7        |«      j8                  }t!        |«      S # t        $ r d}Y �Œlw xY w)uÖ  
        Timeline "marchÃ©": 1 call pour alimenter la page dÃ©tail dossier.
        GET /api/collection-cases/<id>/timeline/?limit_actions=50

        âœ… Fix: ne pas slicer dans Prefetch queryset (sinon Django crash).
        On slice en Python aprÃ¨s le prefetch.

        âœ… AmÃ©lioration: calcule Total payÃ© / Solde depuis les paiements prefetched,
        donc l'affichage reste correct mÃªme si un champ dÃ©normalisÃ© est temporairement dÃ©synchronisÃ©.
        Úlimit_actionsr   )r7   Úpkrw   ru   rv   ÚactionsrY   ú-action_dater^   Úpref_actions)ÚquerysetÚto_attrÚpromisesú-promised_dateÚpref_promisesÚpaymentsú-paid_atÚpref_paymentsr—   z
Not found.i”  r„   Nc              3  ó4   K  — | ]  }|j                   –— Œ y ­wrN   )Úamount)Ú.0Úps     r"   ú	<genexpr>z1CollectionCaseViewSet.timeline.<locals>.<genexpr>  s   è ø€ Ò5 q˜!Ÿ(�(Ñ5ùs   ‚z0.00)Ú	total_dueÚ
total_paidÚbalanceÚ
is_overduer=   rg   )Úcaser�   r¢   r¥   Útotals)rl   rm   ÚintÚ
ValueErrorrW   r&   rB   rD   rC   Úprefetch_relatedr   r'   rE   r(   r)   rF   r   Úlistr>   Úsumr   r­   Ústrr°   Úlowerr=   rg   r0   rr   )rP   rG   rœ   r›   r7   rZ   r±   r�   r¢   r¥   Ú
paid_totalr¯   Úpayloadrr   s                 r"   r–   zCollectionCaseViewSet.timelineÆ   s@  € ð  ×,Ñ,×0Ñ0°ÓAˆð	Ù2?œC Ô.ÀRˆMð —‘Ó"ˆô ×"Ñ"ß‰V˜6 bˆVÓ)ß‰^˜M¨;¸ÓAßÑÜØÜ-×5Ñ5ß‘V 6�VÓ*ß‘X˜nÓ-ß#‘^ LÓ1Ø*ôô ØÜ+×3Ñ3ß‘V 6�VÓ*ß‘XÐ.Ó/ß#‘^ LÓ1Ø+ôô ØÜ$Ÿ_™_ß‘V 6�VÓ*ß‘X˜jÓ)ß#‘^ LÓ1Ø+ôó#ð	 	ð@ �x‰x‹zˆÙÜ˜X |Ð4¸SÔAÐAä”w˜t ^°RÓ8Ó9¸.¸=ÐIˆÜœ  o°rÓ:Ó;ˆÜœ  o°rÓ:Ó;ˆäÑ5¨HÔ5´w¸v³ÓGˆ
Ø—.‘. :Ñ-ˆØ”W˜V“_Ò$Ü˜f“oˆGð ØØ Ø ä  §¡Ó0Ü! *›oÜ˜w›<Ü! $§/¡/Ó2×8Ñ8Ó:ØŸ+™+Ø ŸM™Mññ
ˆô 0°Ó8×=Ñ=ˆÜ˜‹~ÐøôG ò 	Ø‹Mð	ús   �J
 Ê
JÊJrN   )r   r   r   r+   Úserializer_classrL   Úpermission_classesr#   r   Úfilter_backendsr%   Úfilterset_classÚordering_fieldsÚorderingr&   rB   rk   r    rp   r•   r   r–   r    r!   r"   rc   rc   y   sl   „ Ø/ÐØ(Ð)ÐØ*¨NÐ;€OØ*€OÚ\€OØˆ€Hà×%Ñ%×)Ñ)Ó+€Hòò:=ñx �4 % °:Ô>òQó ?ñQr!   rc   c                  óB   — e Zd ZeZegZeZe	e
gZddgZdgZd„ Zd„ Zd„ Zy)ÚCollectionActionViewSetÚaction_daterd   rž   c                ó0  — t         j                  j                  ddd«      }| j                  |«      }| j                  j
                  j                  d«      }|r|j                  |¬«      }| j                  j
                  j                  d«      }|r|j                  |¬«      }| j                  j
                  j                  d«      xs dj                  «       }|rFd	d
l	m
} |j                   ||¬«       ||¬«      z   ||¬«      z   ||¬«      z   ||¬«      z  «      }| j                  j
                  j                  d«      }|r|j                  |¬«      }| j                  j
                  j                  d«      }|r|j                  |¬«      }|S )Nr±   Úcase__debtorr^   ©Úcase_idÚaction_type)rÉ   ÚqÚ r   )ÚQ)Úsummary__icontains)Údetails__icontains)Úcase__reference__icontains)Ú"case__debtor__full_name__icontains)Úcase__debtor__name__icontainsÚ	date_from)Úaction_date__date__gteÚdate_to)Úaction_date__date__lte)r'   rB   rC   r[   rG   rl   rm   rD   rn   Údjango.db.modelsrÌ   )rP   rZ   rÈ   rÉ   rÊ   rÌ   rÒ   rÔ   s           r"   rp   z$CollectionActionViewSet.get_queryset'  sc  € Ü×%Ñ%×4Ñ4°V¸^È\ÓZˆØ×"Ñ" 2Ó&ˆà—,‘,×+Ñ+×/Ñ/°Ó7ˆÙØ—‘ 7�Ó+ˆBà—l‘l×/Ñ/×3Ñ3°MÓBˆÙØ—‘ {�Ó3ˆBà�\‰\×&Ñ&×*Ñ*¨3Ó/Ò5°2×<Ñ<Ó>ˆÙÝ*Ø—‘Ù QÔ'Ù QÔ'ñ(á¨QÔ/ñ0ñ °QÔ7ñ8ñ °Ô2ñ	3óˆBð —L‘L×-Ñ-×1Ñ1°+Ó>ˆ	ÙØ—‘°)�Ó<ˆBà—,‘,×+Ñ+×/Ñ/°	Ó:ˆÙØ—‘°'�Ó:ˆBàˆ	r!   c                ó  — | j                  «       }|j                  j                  d«      }|r&|j                  |j                  k7  rt        ddi«      ‚|j                  || j                  j                  ¬«      }t        |«       y )Nr±   ú'Case does not belong to current tenant.r]   )
rW   r‡   rm   Ú	tenant_idÚidr   r_   rG   r8   r1   )rP   r`   r7   r±   Ú
action_objs        r"   ra   z&CollectionActionViewSet.perform_createH  sm   € Ø—‘Ó"ˆØ×(Ñ(×,Ñ,¨VÓ4ˆÙ�D—N‘N f§i¡iÒ/Ü! 6Ð+TÐ"UÓVÐVà—_‘_¨F¸t¿|¹|×?PÑ?P�_ÓQˆ
ô 	˜ZÕ(r!   c                ó:   — |j                  «       }t        |«       y rN   )r_   r1   )rP   r`   rÛ   s      r"   Úperform_updatez&CollectionActionViewSet.perform_updateS  s   € Ø—_‘_Ó&ˆ
Ü˜ZÕ(r!   N)r   r   r   r,   r¼   rL   r½   r   Úpagination_classr#   r   r¾   rÀ   rÁ   rp   ra   rÝ   r    r!   r"   rÃ   rÃ     sC   „ Ø1ÐØ(Ð)ÐØ+ÐØ*¨NÐ;€OØ$ lÐ3€OØÐ€HòòB	)ó)r!   rÃ   c                  ó8   — e Zd ZeZegZeegZ	ddgZ
dgZd„ Zd„ Zy)ÚPaymentPromiseViewSetÚpromised_daterd   r£   c                óØ   — t         j                  j                  d«      }| j                  |«      }| j                  j
                  j                  d«      }|r|j                  |¬«      }|S ©Nr±   rÇ   )r(   rB   rC   r[   rG   rl   rm   rD   ©rP   rZ   rÈ   s      r"   rp   z"PaymentPromiseViewSet.get_querysetc  sZ   € Ü×#Ñ#×2Ñ2°6Ó:ˆØ×"Ñ" 2Ó&ˆØ—,‘,×+Ñ+×/Ñ/°Ó7ˆÙØ—‘ 7�Ó+ˆBØˆ	r!   c                ó¾  — | j                  «       }|j                  j                  d«      }|r&|j                  |j                  k7  rt        ddi«      ‚|j                  || j                  j                  ¬«      }|j                  dk(  rT|j                  rG|j                  }|j                  |_        |j                  xs d|_        |j                  g d¢¬«       y y y )Nr±   rØ   r]   ÚpendingÚcall)rf   r~   re   r�   )rW   r‡   rm   rÙ   rÚ   r   r_   rG   r8   r=   rá   r±   rf   r~   )rP   r`   r7   r±   ÚpromiseÚccs         r"   ra   z$PaymentPromiseViewSet.perform_createk  s»   € Ø—‘Ó"ˆØ×(Ñ(×,Ñ,¨VÓ4ˆÙ�D—N‘N f§i¡iÒ/Ü! 6Ð+TÐ"UÓVÐVà—/‘/¨¸D¿L¹L×<MÑ<M�/ÓNˆð �>‰>˜YÒ&¨7×+@Ò+@Ø—‘ˆBà")×"7Ñ"7ˆBÔØ"$×"5Ñ"5Ò"?¸ˆBÔØ�G‰GÒ"XˆGÕYð ,AÐ&r!   N)r   r   r   r-   r¼   rL   r½   r#   r   r¾   rÀ   rÁ   rp   ra   r    r!   r"   rà   rà   \  s8   „ Ø/ÐØ(Ð)ÐØ*¨NÐ;€OØ&¨Ð5€OØ Ð!€HòóZr!   rà   c                  óD   — e Zd ZeZegZeegZ	ddgZ
dgZd„ Zd„ Zd„ Zd„ Zy)	ÚPaymentViewSetÚpaid_atrd   r¦   c                óØ   — t         j                  j                  d«      }| j                  |«      }| j                  j
                  j                  d«      }|r|j                  |¬«      }|S rã   )r)   rB   rC   r[   rG   rl   rm   rD   rä   s      r"   rp   zPaymentViewSet.get_queryset‡  sX   € Ü�_‰_×+Ñ+¨FÓ3ˆØ×"Ñ" 2Ó&ˆØ—,‘,×+Ñ+×/Ñ/°Ó7ˆÙØ—‘ 7�Ó+ˆBØˆ	r!   c                ó–  — | j                  «       }|j                  j                  d«      }|r&|j                  |j                  k7  rt        ddi«      ‚|j                  j                  d«      xs d}|j                  j                  d«      }|dk7  r)|�'t        |dd «      |j                  k7  rt        ddi«      ‚|dk7  r|€	 d	d
lm}  ||d¬«      }|dk7  r+|�)|j                  || j                  j                  |¬«      }n'|j                  || j                  j                  ¬«      }t        ||d¬«       y # t        $ r d }Y Œsw xY w)Nr±   rØ   Úreceived_byÚacxÚtreasury_accountÚcustomer_directrÙ   z)Invalid treasury account for this tenant.r   ©Úget_default_accountÚXAF©r7   Úcurrency)r7   r^   rñ   r]   F©r7   Úrequire_account)rW   r‡   rm   rÙ   rÚ   r   r>   Útreasury_management.servicesrô   rA   r_   rG   r8   r3   )rP   r`   r7   r±   rï   Útarô   Úpayments           r"   ra   zPaymentViewSet.perform_create�  sC  € Ø—‘Ó"ˆØ×(Ñ(×,Ñ,¨VÓ4ˆÙ�D—N‘N f§i¡iÒ/Ü! 6Ð+TÐ"UÓVÐVà ×/Ñ/×3Ñ3°MÓBÒKÀeˆØ×&Ñ&×*Ñ*Ð+=Ó>ˆð Ð+Ò+°°Ä7È2È{Ð\`ÓCaÐek×enÑenÒCnÜ!Ð#5Ð7bÐ"cÓdÐdð Ð+Ò+°°
ðÝLÙ(°ÀÔG�ð
 Ð+Ò+°°Ø —o‘o¨VÀÇÁ×@QÑ@QÐdf�oÓg‰Gà —o‘o¨VÀÇÁ×@QÑ@Q�oÓRˆGô 	" '°&È%ÖPøô ò Ø’ðús   ÃD: Ä:EÅEc                ó  — | j                  «       }|j                  «       }t        |dd «      dk7  r;t        |dd «      €.	 ddlm}  ||d¬«      }|�||_        |j                  ddg¬	«       t        ||d
¬«       y # t
        $ r d }Y Œ9w xY w)Nrï   rò   rñ   r   ró   rõ   rö   re   r�   Frø   )rW   r_   r>   rú   rô   rA   rñ   r3   )rP   r`   r7   rü   rô   rû   s         r"   rÝ   zPaymentViewSet.perform_update®  s˜   € Ø—‘Ó"ˆØ—/‘/Ó#ˆô �7˜M¨4Ó0Ð4EÒEÌ'ÐRYÐ[mÐosÓJtÐJ|ðÝLÙ(°ÀÔG�ð ˆ~Ø+-�Ô(Ø—‘Ð,>ÀÐ+M�ÔNä! '°&È%ÖPøô ò Ø’ðús   ¿A; Á;B	ÂB	c                ó–  — | j                  «       }|j                  }	 ddlm} |j                  j                  |d|j                  › �¬«      j                  |j                  j                  d ¬«       	 |j                  «        t        |d¬	«       y # t        $ r Y Œ*w xY w# t        $ r}t        ddt        |«      › �i«      ‚d }~ww xY w)
Nr   )ÚTreasuryMovementzpayment:)r7   Ú
source_key)r=   rü   r—   zCannot delete payment: T)Úsync_core_case)rW   r±   Útreasury_management.modelsrÿ   rB   rD   rÚ   ÚupdateÚStatusÚ	CANCELLEDrA   Údeleter   r¸   r2   )rP   Úinstancer7   r±   rÿ   Úes         r"   Úperform_destroyzPaymentViewSet.perform_destroy¿  sÉ   € Ø—‘Ó"ˆØ�}‰}ˆð	ÝCØ×$Ñ$×+Ñ+°6ÈÐQY×Q\ÑQ\ÐP]ÐF^Ð+Ó_×fÑfØ'×.Ñ.×8Ñ8Øð gô ð	RØ�O‰OÔô
 	  °TÖ:øô ò 	Ùð	ûô
 ò 	Rä! 8Ð/FÄsÈ1ÃvÀhÐ-OÐ"PÓQÐQûð	Rús*   žAB Á4B! Â	BÂBÂ!	CÂ*CÃCN)r   r   r   r.   r¼   rL   r½   r#   r   r¾   rÀ   rÁ   rp   ra   rÝ   r	  r    r!   r"   rë   rë   €  sB   „ Ø(ÐØ(Ð)ÐØ*¨NÐ;€OØ  ,Ð/€OØˆ|€HòòQò>Qó";r!   rë   c                  óÒ   ‡ — e Zd ZeZegZeegZ	g d¢Z
ddgZej                  j                  «       Zd„ Zˆ fd„Z eddgdeeeg¬	«      d
„ «       Z eddgdeeeg¬	«      d„ «       Zˆ xZS )ÚCollectionEmailViewSet)Úsent_atrd   re   z-sent_atz-created_atc                óD  — | j                  t        j                  j                  «       «      }| j                  j
                  j                  d«      }|r|j                  |¬«      }| j                  j
                  j                  d«      }|r|j                  |¬«      }|S )Nr±   rÇ   r   )Ú	action_id)r[   r*   rB   rk   rG   rl   rm   rD   )rP   rZ   rÈ   r  s       r"   rp   z#CollectionEmailViewSet.get_querysetã  s€   € Ø×"Ñ"¤?×#:Ñ#:×#>Ñ#>Ó#@ÓAˆØ—,‘,×+Ñ+×/Ñ/°Ó7ˆÙØ—‘ 7�Ó+ˆBØ—L‘L×-Ñ-×1Ñ1°(Ó;ˆ	ÙØ—‘ Y�Ó/ˆBØˆ	r!   c                óB   •— t         ‰| �  «       }| j                  |d<   |S )NrG   )ÚsuperÚget_serializer_contextrG   )rP   ÚctxÚ	__class__s     €r"   r  z-CollectionEmailViewSet.get_serializer_contextí  s"   ø€ Ü‰gÑ,Ó.ˆØŸ™ˆˆI‰Øˆ
r!   FÚPOSTÚattach)r—   r˜   r™   Úparser_classesc                óð  — | j                  «       }|j                  j                  d«      xs |j                  j                  d«      }|st        ddi«      ‚	 t	        |«      }t        j                  j                  ||¬«      j                  «       }|st        ddi«      ‚|j                  j                  d«      xs |j                  j                  d«      }d	}|rg	 t	        |«      }t        j                  j                  |||¬«      j                  «       }|st        ddi«      ‚|j                  dk7  rt        ddi«      ‚|j                  j                  d«      xs |j                  j                  d«      }|st        ddi«      ‚t        |dd«      xs dj                  «       }|j                  d«      st        ddi«      ‚|j                  j                  d«      xs dj!                  «       j                  «       }	|j                  j                  d«      xs dj!                  «       j                  «       }
|j                  j                  d«      xs dj!                  «       }t#        ||||j$                  ||	|
|d¬«	      \  }}| j'                  |«      j                  }|j(                  |d<   t+        |d¬«      S # t
        $ r t        ddi«      ‚w xY w# t
        $ r t        dd
i«      ‚w xY w) u¡  
        POST /api/collection-emails/attach/
        Form-data:
        - case (required): CollectionCase id
        - action (optional): CollectionAction id (pour attacher Ã  une action email existante)
        - file (required): .eml (export Outlook)
        - notes (optional)
        - direction (optional): outbound|inbound (default outbound)
        - source (optional): outlook|other (default outlook)
        r±   rÈ   úcase is requiredúcase must be an integer id©r7   rÚ   ú"Case not found for current tenant.r   r  Núaction must be an integer id©r7   rÚ   r±   ú)Action not found for current tenant/case.ÚemailúAction must be of type 'email'.ÚfileÚemlzfile (.eml) is requiredÚnamerË   z.emlz/Only .eml files are supported (export Outlook).Ú	directionÚoutboundÚsourceÚoutlookr   T)	r7   r±   Úeml_filer^   r   r$  r&  r   Úcreate_action_if_missingÚtimeline_action_idrƒ   r„   )rW   rr   rm   r   r³   rA   r&   rB   rD   rF   r'   rÉ   ÚFILESr>   r¹   Úendswithrn   r5   r8   r…   rÚ   r   )rP   rG   r7   rÈ   r±   r  rÛ   ÚfÚfilenamer$  r&  r   Ú	email_objÚaction_obj2rr   s                  r"   r  zCollectionEmailViewSet.attachò  sË  € ð" —‘Ó"ˆà—,‘,×"Ñ" 6Ó*ÒI¨g¯l©l×.>Ñ.>¸yÓ.IˆÙÜ! 6Ð+=Ð">Ó?Ð?ð	JÜ˜'“lˆGô ×%Ñ%×,Ñ,°F¸wÐ,ÓG×MÑMÓOˆÙÜ! 6Ð+OÐ"PÓQÐQà—L‘L×$Ñ$ XÓ.ÒO°'·,±,×2BÑ2BÀ;Ó2Oˆ	Øˆ
ÙðRÜ 	›N�	ô *×1Ñ1×8Ñ8ÀÈ9Ð[_Ð8Ó`×fÑfÓhˆJÙÜ% xÐ1\Ð&]Ó^Ð^Ø×%Ñ%¨Ò0Ü% xÐ1RÐ&SÓTÐTà�M‰M×Ñ˜fÓ%ÒA¨¯©×):Ñ):¸5Ó)AˆÙÜ! 6Ð+DÐ"EÓFÐFä˜A˜v rÓ*Ò0¨b×7Ñ7Ó9ˆØ× Ñ  Ô(Ü! 6Ð+\Ð"]Ó^Ð^ð —\‘\×%Ñ% kÓ2Ò@°j×GÑGÓI×OÑOÓQˆ	Ø—,‘,×"Ñ" 8Ó,Ò9°	×@Ñ@ÓB×HÑHÓJˆØ—‘×!Ñ! 'Ó*Ò0¨b×7Ñ7Ó9ˆä!3ØØØØ—|‘|ØØØØØ%)ô
"
Ñˆ	�;ð ×"Ñ" 9Ó-×2Ñ2ˆØ%0§^¡^ˆÐ!Ñ"Ü˜ SÔ)Ð)øô_ ò 	JÜ! 6Ð+GÐ"HÓIÐIð	Jûô ò RÜ% xÐ1OÐ&PÓQÐQðRús   ÁK ÃK ËKËK5Úsendc                óÖ  — | j                  «       }|j                  j                  d«      xs |j                  j                  d«      }|st        ddi«      ‚	 t	        |«      }t        j                  j                  ||¬«      j                  «       }|st        ddi«      ‚|j                  j                  d«      xs |j                  j                  d«      }d	}|rg	 t	        |«      }t        j                  j                  |||¬«      j                  «       }|st        ddi«      ‚|j                  dk7  rt        ddi«      ‚d„ } ||j                  j                  d«      «      }|st        ddi«      ‚ ||j                  j                  d«      «      }	 ||j                  j                  d«      «      }
|j                  j                  d«      xs dj                  «       }|j                  j                  d«      xs |j                  j                  d«      xs dj                  «       }|j                  j                  d«      xs dj                  «       }|j                  j                  d«      xs dj                  «       xs d	}|j                  j                  d«      xs dj                  «       }|j                  j                  d«      xs g }t        ||||	|
||||||j                   ||¬«      \  }}| j#                  |«      j                  }|j$                  |d<   t'        |d¬«      S # t
        $ r t        ddi«      ‚w xY w# t
        $ r t        dd
i«      ‚w xY w) uê  
        POST /api/collection-emails/send/
        Form-data:
        - case (required): CollectionCase id
        - to (required): "a@x.com,b@y.com" (ou JSON list)
        - cc (optional), bcc (optional)
        - subject (optional)
        - body_text / body_html (optional)
        - from_address (optional)
        - notes (optional)
        - action (optional): CollectionAction id (type=email) Ã  rÃ©utiliser
        - attachments (optional): multiples fichiers "attachments"
        r±   rÈ   r  r  r  r  r   r  Nr  r  r  r  r   c                óÌ  — | €g S t        | t        t        f«      rA| D �cg c]5  }t        |«      j	                  «       sŒt        |«      j	                  «       ‘Œ7 c}S t        | «      j	                  «       }|sg S |j                  d«      ry|j                  d«      rh	 dd l}|j                  |«      }t        |t        «      rA|D �cg c]5  }t        |«      j	                  «       sŒt        |«      j	                  «       ‘Œ7 c}S 	 t        j                  d|«      }|D �cg c]#  }|j	                  «       sŒ|j	                  «       ‘Œ% c}S c c}w c c}w # t        $ r Y ŒZw xY wc c}w )Nú[ú]r   z[;,])Ú
isinstancer¶   Útupler¸   rn   Ú
startswithr,  ÚjsonÚloadsrA   ÚreÚsplit)ÚvÚxÚsr9  ÚarrÚpartsr«   s          r"   Ú_parse_emailsz2CollectionEmailViewSet.send.<locals>._parse_emailsk  s  € ØˆyØ�	Ü˜!œd¤E˜]Ô+Ø01ÖD¨1´S¸³V·\±\µ^œ˜A›Ÿ™�ÒDÐDÜ�A“—‘“ˆAÙØ�	à�|‰|˜CÔ  Q§Z¡Z°¤_ðÛØŸ*™* Q›-�CÜ! #¤tÔ,Ø8;ÖN°1¼sÀ1»v¿|¹|½~¤ A£§¡¥ÒNÐNð -ô
 —H‘H˜W aÓ(ˆEØ',Ö: !°·±µ	�A—G‘G•IÒ:Ð:ùò Eùò  OøÜ ò Ùðüò ;s@   ŸE¾EÂ)E ÃEÃ$EÃ?E ÄE!Ä3E!ÅE Å	EÅEÚtoz$to is required (one or more emails).ré   ÚbccÚsubjectrË   Ú	body_textÚbodyÚ	body_htmlÚfrom_addressr   Úattachments)r7   r±   rC  ré   rD  rE  rF  rH  rI  r   r^   r   rJ  r*  rƒ   r„   )rW   rr   rm   r   r³   rA   r&   rB   rD   rF   r'   rÉ   rn   r+  Úgetlistr4   r8   r…   rÚ   r   )rP   rG   r7   rÈ   r±   r  rÛ   rB  rC  ré   rD  rE  rF  rH  rI  r   Úfilesr/  r0  rr   s                       r"   r1  zCollectionEmailViewSet.send<  s)  € ð( —‘Ó"ˆà—,‘,×"Ñ" 6Ó*ÒI¨g¯l©l×.>Ñ.>¸yÓ.IˆÙÜ! 6Ð+=Ð">Ó?Ð?ð	JÜ˜'“lˆGô ×%Ñ%×,Ñ,°F¸wÐ,ÓG×MÑMÓOˆÙÜ! 6Ð+OÐ"PÓQÐQà—L‘L×$Ñ$ XÓ.ÒO°'·,±,×2BÑ2BÀ;Ó2Oˆ	Øˆ
ÙðRÜ 	›N�	ô *×1Ñ1×8Ñ8ÀÈ9Ð[_Ð8Ó`×fÑfÓhˆJÙÜ% xÐ1\Ð&]Ó^Ð^Ø×%Ñ%¨Ò0Ü% xÐ1RÐ&SÓTÐTò	;ñ* ˜7Ÿ<™<×+Ñ+¨DÓ1Ó2ˆÙÜ! 4Ð)OÐ"PÓQÐQá˜7Ÿ<™<×+Ñ+¨DÓ1Ó2ˆÙ˜GŸL™L×,Ñ,¨UÓ3Ó4ˆØ—<‘<×#Ñ# IÓ.Ò4°"×;Ñ;Ó=ˆØ—\‘\×%Ñ% kÓ2ÒT°g·l±l×6FÑ6FÀvÓ6NÒTÐRT×[Ñ[Ó]ˆ	Ø—\‘\×%Ñ% kÓ2Ò8°b×?Ñ?ÓAˆ	ØŸ™×(Ñ(¨Ó8Ò>¸B×EÑEÓGÒOÈ4ˆØ—‘×!Ñ! 'Ó*Ò0¨b×7Ñ7Ó9ˆà—‘×%Ñ% mÓ4Ò:¸ˆÜ!/ØØØØØØØØØ%ØØ—|‘|ØØô"
Ñˆ	�;ð  ×"Ñ" 9Ó-×2Ñ2ˆØ%0§^¡^ˆÐ!Ñ"Ü˜ SÔ)Ð)øôQ ò 	JÜ! 6Ð+GÐ"HÓIÐIð	Jûô ò RÜ% xÐ1OÐ&PÓQÐQðRús   ÁL7 ÃM Ì7MÍM()r   r   r   r/   r¼   rL   r½   r#   r   r¾   rÀ   rÁ   r*   rB   rk   r    rp   r  r   r   r   r   r  r1  Ú__classcell__)r  s   @r"   r  r  Ú  sª   ø„ Ø0ÐØ(Ð)ÐØ*¨NÐ;€OÚ=€OØ˜MÐ*€Hà×&Ñ&×*Ñ*Ó,€Hòôñ
 ØØ�ØØ'¨°ZÐ@ô	ñB*óðB*ñH ØØ�ØØ'¨°ZÐ@ô	ñ]*óô]*r!   r  )ÚdateÚ	timedelta)ÚCountÚSumrÌ   )Ú
TruncMonth)ÚAPIViewc                  ó   — e Zd ZegZd„ Zy)ÚTenantStatsViewc                óŽ  — t        |«      }|st        ddid¬«      S t        j                  j	                  |¬«      }|j                  t        d«      t        d«      t        d«      t        d	«      t        d
«      t        d«      t        dt        t        j                  «       d¬«      ¬«      ¬«      }t        |d   xs d|d   xs dz   |d   xs dz   |d   xs dz   «      }t        |d   xs d«      }|dkD  rt        ||z  dz  d«      nd}|j                  d«      j                  t        d«      t        d«      ¬«      D �cg c]  }|d   |d   t        |d   xs d«      dœ‘Œ  }	}|j                  d«      j                  t        d«      ¬«      D �
cg c]  }
|
d   |
d   dœ‘Œ }}
t        j                  «       j                  d¬ «      t!        d!¬"«      z
  }t"        j                  j	                  |¬«      }|j	                  |¬#«      j                  t%        d$«      ¬%«      j                  d&«      j                  t        d'«      t        d«      ¬(«      j'                  d&«      D �cg c]-  }|d&   j)                  d)«      t        |d'   xs d«      |d   d*œ‘Œ/ }}|j                  d+«      j                  t        d«      t        d'«      ¬,«      D �
cg c]  }
|
d+   |
d   t        |
d'   xs d«      d-œ‘Œ  }}
t*        j                  j	                  |¬«      j                  d.«      j                  t        d«      ¬«      j'                  d/«      D �cg c]  }|d.   |d   d0œ‘Œ }}t,        j                  j	                  |¬«      }|j	                  d1¬«      j/                  «       |j	                  d2¬«      j/                  «       |j	                  d3¬«      j/                  «       |j	                  d4¬«      j/                  «       d5œ}t        |d6   xs d|d7   xs d||||	|d8œ||d9œd:|i|d;œ«      S c c}w c c}
w c c}w c c}
w c c}w )<Nr—   zTenant context missing.i“  r„   rY   rÚ   r|   rx   ry   rz   r{   F)Únext_action_date__ltÚnext_action_date__isnull)rD   )Útotalr®   Ú	principalÚinterestÚpenaltyÚfeesÚoverduerZ  r   r[  r\  r]  r®   éd   r$   g        r=   )Úcountr®   r`  )r=   r`  r®   rg   )r`  )rg   r`  )Údayé–   )Údays)Úpaid_at__date__gterì   )Úmonthre  r©   )r©   r`  z%Y-%m)re  r©   r`  Úmethod)r`  r©   )rf  r`  r©   rÉ   z-count)Útyper`  ræ   ÚkeptÚbrokenÚ	cancelled)ræ   rh  ri  rj  rY  r^  )rY  r^  Útotal_amountr®   Úrecovery_rateÚ	by_statusÚby_priority)Ú	by_methodÚmonthly_trendÚby_type)Úcasesr¥   r�   r¢   )rJ   r   r&   rB   rD   Ú	aggregaterP  rQ  rÌ   rN  ÚtodayÚfloatÚroundÚvaluesÚannotateÚreplacerO  r)   rR  rE   Ústrftimer'   r(   r`  )rP   rG   r7   rr  r²   rk  r®   rl  r?  rm  r«   rn  Úsix_months_agoÚpayments_qsrI   Úmonthlyro  ÚaÚby_action_typeÚpromises_qsr¢   s                        r"   rm   zTenantStatsView.get¯  sg  € Ü,¨WÓ5ˆÙÜ˜XÐ'@ÐAÈ#ÔNÐNä×&Ñ&×-Ñ-°VÐ-Ó<ˆð —‘Ü˜“+ÜÐ.Ó/ÜÐ,Ó-ÜÐ*Ó+ÜÐ(Ó)Ü�]Ó#Ü˜$¤qÜ%)§Z¡Z£\Ø).ô(ô ð !ó 
ˆô Ø�KÑ Ò% AØ�jÑ!Ò& Qñ(à�iÑ Ò% Añ'ð �f‰~Ò" ñ$ó
ˆô ˜6 ,Ñ/Ò4°1Ó5ˆ
ØEQÐTUÒEUœ˜j¨<Ñ7¸#Ñ=¸qÔAÐ[^ˆð
 —\‘\ (Ó+×4Ñ4¼5À»;ÔSVÐWjÓSkÐ4Ólö
àð ˜‘{¨Q¨w©ZÄuÈQÈ|É_ÒMaÐ`aÓGbÓcð
ˆ	ð 
ð —\‘\ *Ó-×6Ñ6¼UÀ4»[Ð6ÓIö
àð ˜:™°°7±Ó<ð
ˆð 
ô Ÿ™›×-Ñ-°!Ð-Ó4´yÀcÔ7JÑJˆÜ—o‘o×,Ñ,°FÐ,Ó;ˆð ß‘¨>�Ó:ß‘¤
¨9Ó 5�Ó6ß‘˜“ß‘¤ X£´e¸D³k�ÓBß‘˜'Ó"ö
ð ð	 ˜7™×,Ñ,¨WÓ5Ü  (¡Ò 0¨qÓ1Ø˜7™óð
ˆð 
ð$ !×'Ñ'¨Ó1×:Ñ:ÄÀtÃÔUXÐYaÓUbÐ:Ócö
àð ˜‘{¨Q¨w©ZÄ5ÈÈ8ÉÒIYÐXYÓCZÓ[ð
ˆ	ð 
ô !×(Ñ(ß‘˜v�Ó&ß‘˜Ó&ß‘¤ d£�Ó,ß‘˜(Ó#ö	
àð �}Ñ%°°'±
Ó;ð	
ˆð 	
ô %×,Ñ,×3Ñ3¸6Ð3ÓBˆà$×+Ñ+°9Ð+Ó=×CÑCÓEØ$×+Ñ+°6Ð+Ó:×@Ñ@ÓBØ$×+Ñ+°8Ð+Ó<×BÑBÓDØ$×+Ñ+°;Ð+Ó?×EÑEÓGñ	
ˆô à!'¨¡Ò!5°AØ!'¨	Ñ!2Ò!7°aØ!-Ø!+Ø!.Ø!*Ø!,ñð "+Ø!(ñð
 ˜>ðð !ñ#
ó ð 	ùòs
ùò
ùò
ùò 
ùò	
s   Å#P.ÆP3É(2P8Ë#P=ÍQN)r   r   r   rL   r½   rm   r    r!   r"   rU  rU  ¬  s   „ Ø(Ð)Ðóir!   rU  )LÚ
__future__r   r;  Údecimalr   Údjango.appsr   Ú	django.dbr   r   rÖ   r   Úrest_frameworkr	   r
   Úrest_framework.parsersr   r   r   Úrest_framework.decoratorsr   Úrest_framework.exceptionsr   r   Úrest_framework.filtersr   Úrest_framework.paginationr   Úrest_framework.responser   r   Údjango_filters.rest_frameworkr#   Úfiltersr%   Úmodelsr&   r'   r(   r)   r*   Úserializersr+   r,   r-   r.   r/   Úserializers_timeliner0   Úservicesr1   r2   r3   r4   r5   rJ   ÚBasePermissionrL   rU   ÚModelViewSetrc   rÃ   rà   rë   r  ÚdatetimerN  rO  rP  rQ  rÌ   Údjango.db.models.functionsrR  Úrest_framework.viewsrS  rU  r    r!   r"   ú<module>r—     s#  ðõ #ã 	å å ß 1Ý %ç 0ß JÑ JÝ ,ß GÝ 1Ý :Ý ,ôÐ/ô õ >å )ß ^Õ ^÷õ õ C÷ Cõ  Cò#ôLD�[×/Ñ/ô D÷Eñ Eô0_Ð5°x×7LÑ7Lô _ôL6)Ð7¸×9NÑ9Nô 6)ôzZÐ5°x×7LÑ7Lô ZôHT;Ð.°×0EÑ0Eô T;ôtE*Ð6¸×8MÑ8Mô E*÷X %ß *Ñ *Ý 1Ý (ôl�gõ lr!   