o
    š�ži@ñ  ã                   @  sl  d dl mZ d dlZd dlZd dlZd dlZd dl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 d dlmZmZmZ d dlZejrgdd	lmZ dd
lmZ ddlmZmZ ddl m!Z! dZ"dddœZ#ej$dd„ ƒZ%dd„ e&ej'dd„ d�D ƒZ(dd„ Z)G dd„ dej*ƒZ+G dd„ dej*ƒZ,G dd„ dej-ƒZ.G d d!„ d!ej-ƒZ/G d"d#„ d#ej-ƒZ0dS )$é    )ÚannotationsN)Údefaultdict©Úrandint)Úurls)ÚapiÚfieldsÚmodelsÚtoolsÚ_ÚCommand)ÚRedirectWarningÚ	UserErrorÚValidationErroré   )ÚResUsers)ÚResPartnerBank)Ú
ResCountryÚResCountryState)Ú
ResCompany)ÚstreetÚstreet2ÚzipÚcityÚstate_idÚ
country_idÚELÚXI)ÚGRÚGBc                 C  s   | j d  ¡ S ©Nzres.lang)ÚenvÚget_installed©Úself© r%   ú?/home/minischoggi19/odoo/odoo/addons/base/models/res_partner.pyÚ	_lang_get"   ó   r'   c                 C  s   g | ]}||f‘qS r%   r%   )Ú.0Útzr%   r%   r&   Ú
<listcomp>(   ó    r+   c                 C  s   |   d¡s| S dS )NzEtc/r   )Ú
startswith)r*   r%   r%   r&   Ú<lambda>(   ó    r.   ©Úkeyc                 C  s   t S ©N)Ú_tzsr#   r%   r%   r&   Ú_tz_get)   ó   r4   c                      s,   e Zd ZdZdZejd‡ fdd„	ƒZ‡  ZS )ÚFormatVatLabelMixinúformat.vat.label.mixinzCountry Specific VAT LabelNÚformc                   sj   t ƒ j||fi |¤Ž\}}| jjjj }r1| d¡D ]}| d|¡ q| d¡D ]}| d|¡ q(||fS )Nz.//field[@name='vat']Ústringz.//label[@for='vat'])ÚsuperÚ	_get_viewr!   Úcompanyr   Ú	vat_labelÚiterfindÚset)r$   Úview_idÚ	view_typeÚoptionsÚarchÚviewr=   Únode©Ú	__class__r%   r&   r;   1   s   zFormatVatLabelMixin._get_view©Nr8   )	Ú__name__Ú
__module__Ú__qualname__Ú_nameÚ_descriptionr   Úmodelr;   Ú__classcell__r%   r%   rF   r&   r6   -   s
    r6   c                      sP   e Zd ZdZdZdd„ Zdd„ Zejd‡ fd	d
„	ƒZ	ejd‡ fdd„	ƒZ
‡  ZS )ÚFormatAddressMixinúformat.address.mixinzAddress Formatc                   s.   dd„ t d D ƒ}t‡ fdd„|D ƒˆ jd�S )z³
        Extract keys from the address line.
        For example, if the address line is "zip: %(zip)s, city: %(city)s.",
        this method will return ['zip', 'city'].
        c                 S  s   g | ]}d | d ‘qS )z%(z)sr%   ©r)   Úfieldr%   r%   r&   r+   G   ó    zCFormatAddressMixin._extract_fields_from_address.<locals>.<listcomp>©Ú
state_codeÚ
state_namec                   s    g | ]}|ˆ v r|d d… ‘qS )é   éþÿÿÿr%   rR   ©Úaddress_liner%   r&   r+   H   ó     r0   )ÚADDRESS_FIELDSÚsortedÚindex)r$   r[   Úaddress_fieldsr%   rZ   r&   Ú_extract_fields_from_addressA   s   z/FormatAddressMixin._extract_fields_from_addressc              	     sò  ˆ j jjj ¡ }ˆ j jjj}|roˆ j j d¡so|jr |jˆ j	kro| 
d¡D ]G}ˆ j d jdd�}| |jd¡\}}ˆ j	dkrYzˆ j d j|ˆ j	d� W n tyX   | Y   S w | d	¡}|d urd|}| ¡  ||¡ q%|S |r÷ˆ j j d¡s÷‡ fd
d„| d¡D ƒ}	|	r÷|	d }
| 
d¡D ]g}|
d dvr›|
d nd}h d£|h }| d|› d�¡}|
dd … D ]%}|dv r»d}|}| d|› d�¡}|d urÓ|d urÓ| |¡ ||h8 }q³|D ]}|}| d|› d�¡}|d urõ|d urõ| |¡ qÛq�|S )NÚno_address_formatz#//div[hasclass('o_address_format')]úres.partnerT)rb   r8   z
ir.ui.view)rN   z!.//div[@class="o_address_format"]c                   s   g | ]}d |v rˆ   |¡‘qS )r   )ra   )r)   Úliner#   r%   r&   r+   a   ó    z8FormatAddressMixin._view_get_address.<locals>.<listcomp>Ú
r   rU   r   >   r   r   r   z.//field[@name='z']r   )r!   r<   r   Úaddress_view_idÚsudoÚaddress_formatÚcontextÚgetrN   rL   ÚxpathÚwith_contextr;   ÚidÚpostprocess_and_fieldsÚ
ValueErrorÚfindÚ	getparentÚreplaceÚsplitÚaddnext)r$   rC   rg   ri   Úaddress_nodeÚPartnerÚsub_archÚ	_sub_viewÚnew_address_nodeÚ	city_lineÚfield_orderÚfirst_fieldÚconcerned_fieldsÚcurrent_fieldrS   Úprevious_fieldr%   r#   r&   Ú_view_get_addressJ   sR   $
ÿ
æ

€üz$FormatAddressMixin._view_get_addressNr8   c                   s0   t ƒ j||fi |¤Ž}|| jj| jj d¡f S )zþThe override of _get_view, using _view_get_address,
        changing the architecture according to the address view of the company,
        makes the view cache dependent on the company.
        Different companies could use each a different address viewrb   )r:   Ú_get_view_cache_keyr!   r<   rj   rk   )r$   r@   rA   rB   r1   rF   r%   r&   r‚   z   s   z&FormatAddressMixin._get_view_cache_keyc                   s6   t ƒ j||fi |¤Ž\}}|jdkr|  |¡}||fS rH   )r:   r;   Útyper�   )r$   r@   rA   rB   rC   rD   rF   r%   r&   r;   ƒ   s   

zFormatAddressMixin._get_viewrH   )rI   rJ   rK   rL   rM   ra   r�   r   rN   r‚   r;   rO   r%   r%   rF   r&   rP   =   s    	0rP   c                      sè   e Zd ZU dZdZdZdZdd„ Zej	dddd�Z
ejd	ed
d�Zejddddd�Zd ed< ejdddd�Zd ed< ejddd�Zej	dd�Zejddddd
d�Zded< e d¡dd„ ƒZe d¡dd „ ƒZej‡ fd!d"„ƒZ‡  ZS )#ÚResPartnerCategoryúres.partner.categoryzPartner Tagsúname, idTc                 C  s
   t ddƒS )Nr   é   r   r#   r%   r%   r&   Ú_get_default_color‘   ó   
z%ResPartnerCategory._get_default_colorÚName)ÚrequiredÚ	translateÚColorF)r9   ÚdefaultÚ
aggregatorÚCategoryÚcascade)r9   r_   ÚondeleteÚ	parent_idz
Child Tags©r9   Ú	child_idszEThe active field allows you to hide the category without removing it.)rŽ   Úhelp©r_   rc   Úcategory_idÚ
partner_idÚPartners)Úcolumn1Úcolumn2r9   ÚcopyÚ
ResPartnerÚpartner_idsc                 C  ó   |   ¡ r
ttdƒƒ‚d S )Nz"You can not create recursive tags.©Ú
_has_cycler   r   r#   r%   r%   r&   Ú_check_parent_idœ   ó   ÿz#ResPartnerCategory._check_parent_idc                 C  sD   | D ]}g }|}|r|  |jpd¡ |j}|s
d t|ƒ¡|_qdS )zd Return the categories' display name, including their direct
            parent by default.
        Ú z / N)ÚappendÚnamer“   ÚjoinÚreversedÚdisplay_name)r$   ÚcategoryÚnamesÚcurrentr%   r%   r&   Ú_compute_display_name¡   s   þúz(ResPartnerCategory._compute_display_namec                   s@   t ƒ  ||¡}| d¡r| d¡rtS ddt|  |¡ƒfgS |S )NÚlikeÚnotrn   Úchild_of)r:   Ú_search_display_nameÚendswithr-   ÚNotImplementedÚtupleÚ_search)r$   ÚoperatorÚvalueÚdomainrF   r%   r&   r²   ®   s   

z'ResPartnerCategory._search_display_name)rI   rJ   rK   rL   rM   Ú_orderÚ_parent_storerˆ   r   ÚCharr§   ÚIntegerÚcolorÚMany2oner“   Ú__annotations__ÚOne2manyr•   ÚBooleanÚactiveÚparent_pathÚ	Many2manyrŸ   r   Ú
constrainsr£   Údependsr®   rN   r²   rO   r%   r%   rF   r&   r„   ‹   s&   
 

r„   c                	      sº	  e Zd ZU dZdZg d¢ZdZg d¢ZdZdZ	e
jZdZd	d
„ Zej‡ fdd„ƒZejddd�Zejdddd�Zejdddd�Zd ed< ejdddd�Zejddddgddid�Zd ed< ejddd�Zejedddddd�Zej dd �Z!eje"d!d"d#„ d$d%�Z#ejd&d'd(�Z$ejd)d*d+dddd,d-�Z%d.ed/< ejd0dd1d2�Z&ejd3d4d5�Z'ejdd6d7dd8�Z(d ed9< ejdd:d7dd8�Z)d ed;< ejd<d=ddd>d?d@�Z*ejdAdBd5�Z+ejdCd �Z,ejdDdEdFdG�Z-dHedI< e dJ¡Z.ej/dKdG�Z0ej1dLdEdMdNedO�Z2dPedM< ej3ddQ�Z4ej3dRdS�Z5ejdTdG�Z6ejg dU¢dVdWdX�Z7ejdYdZd �Z8e ¡ Z9e ¡ Z:ejdd[�Z;e ¡ Z<ejd\d]d^d_d`�Z=daedb< ejdcddd^de�Z>dfedg< ejdhdidj�Z?ej@dkdldm�ZAej@dndldm�ZBe ¡ ZCejdodpdqdr�ZDe ¡ ZEej3dsddtd%�ZFej3duddv�ZGe dwdx¡ZHdyedz< ejd{d|d}gd~dd€�ZIejd�d‚ddƒ�ZJd„ed…< ej d†d‡dX�ZKejd)dEdˆdd‰�ZLd.edŠ< ejd)d‹dŒd�dŽ�ZMd.ed�< ej3d�d‘dd’d“�ZNejd”d•d(�ZOejdd–d—dddd˜�ZPd ed™< ejdšd›ddœ�ZQe d�¡ZRejdždddŸ�ZSejdd d¡�ZTd ed¢< ejUd£d¤d5�ZVd¥d¦„ ZWd§d¨„ ZXe
 Yd©dª¡ZZd«d¬„ Z[e \d­d®d¯d°d±¡‡ fd²d³„ƒZ]e \d­d®d´d°d±¡‡ fdµd¶„ƒZ^e \d­d®d·d°d±¡‡ fd¸d¹„ƒZ_e \d­d®dºd°d±¡‡ fd»d¼„ƒZ`e \d­d®d½d°d±¡‡ fd¾d¿„ƒZa‡ fdÀdÁ„Zb‡ fdÂdÃ„ZcdÄdÅ„ Zde \d°d­dd±dÆdÇ¡dÈdÉ„ ƒZee \d¡dÊdË„ ƒZfe \dÌ¡dÍdÎ„ ƒZge \dÏ¡dÐdÑ„ ƒZhe \d¡dÒdÓ„ ƒZie jdÔ¡e \dÕd®¡dÖd×„ ƒƒZke \d®dÕ¡dØdÙ„ ƒZle \dÚd…dÛdg¡dÜdÝ„ ƒZme jdÞ¡dßdà„ ƒZne \dd±¡dádâ„ ƒZoe \dãd#„ ¡dädå„ ƒZpdædç„ Zqe \d°dè¡dédê„ ƒZre \dÆdëdì¡dídî„ ƒZsdïdð„ Zte \dg¡dñdò„ ƒZudódô„ Zvdõdö„ Zwe xd¡d÷dø„ ƒZye xd…¡dùdú„ ƒZz�dh‡ fdüdý„	Z{e |d¡dþdÿ„ ƒZ}e |dg¡�d �d„ ƒZ~e |db¡�d�d„ ƒZe |dd…¡�d�d„ ƒZ€e \d­�d¡�d�d„ ƒZ�e \d°¡�d	�d
„ ƒZ‚�d�d„ Zƒe |�d¡�d�d„ ƒZ„e x�d¡�d�d„ ƒZ…�d�d„ Z†ej�d�d„ ƒZ‡ej�d�d„ ƒZˆ�d�d„ Z‰‡ f�d�d„ZŠej�d�d„ ƒZ‹ej�d�d „ ƒZŒ�d!�d"„ Z��d#�d$„ ZŽej�d%�d&„ ƒZ��d'�d(„ Z��d)�d*„ Z‘�dh�d+�d,„Z’�d-�d.„ Z“�d/�d0„ Z”�d1�d2„ Z•�d3�d4„ Z–�d5�d6„ Z—‡ f�d7�d8„Z˜ej™‡ f�d9�d:„ƒZšej›d�d;��d<�d=„ ƒZœ‡ f�d>�d?„Z��d@�dA„ Zž�dB�dC„ ZŸ�dD�dE„ Z e \�dF�ddÚdbdgdÇ¡e j�dG�dH�dI�dJdÌ�dK¡�dL�dM„ ƒƒZ¡ej�dN�dO„ ƒZ¢ej�di�dP�dQ„ƒZ£�dh�dR�dS„Z¤ej‡ f�dT�dU„ƒZ¥ej�dV�dW„ ƒZ¦ej�dX�dY„ ƒZ§�di�dZ�d[„Z¨�di�d\�d]„Z©�d^�d_„ Zªej�d`�da„ ƒZ«ej�db�dc„ ƒZ¬�dd�de„ Z­�df�dg„ Z®‡  Z¯S (j  rž   rc   ÚContact)rQ   r7   zavatar.mixinz properties.base.definition.mixinzcomplete_name ASC, id DESC)Úcomplete_nameÚemailÚrefÚvatÚcompany_registryFT)ÚinvoiceÚdeliveryÚotherc                 C  s   | j d  | j j d¡¡S )Nr…   r˜   )r!   Úbrowserj   rk   r#   r%   r%   r&   Ú_default_categoryÅ   s   zResPartner._default_categoryc                   sr   t ƒ  |¡}d|v r| d¡r|  | d¡¡}|jj|d< d|v r7| d¡r7|d | jd  | j¡vr7d|d< |S )zMAdd the company of the parent as default if we are creating a child partner. r“   Ú
company_idrƒ   N)	r:   Údefault_getrk   rÑ   rÓ   rn   Ú_fieldsÚ
get_valuesr!   )r$   r   ÚvaluesÚparentrF   r%   r&   rÔ   È   s   zResPartner.default_get)r_   Údefault_export_compatibleÚ_compute_complete_name)ÚcomputeÚstorer_   zRelated Company)r9   r_   r“   zparent_id.namezParent name)ÚrelatedÚreadonlyr9   )rÃ   Ú=TÚactive_test)r9   r¹   rj   r•   Ú	ReferenceÚLanguageÚ_compute_langzVAll the emails and documents sent to this contact will be translated in this language.)r9   rÛ   rÞ   rÜ   r–   Ú_compute_active_lang_count)rÛ   ÚTimezonec                 C  s   | j j d¡S )Nr*   )r!   rj   rk   r#   r%   r%   r&   r.   ß   s    zResPartner.<lambda>a	  When printing documents and exporting/importing data, time values are computed according to this timezone.
If the timezone is not set, UTC (Coordinated Universal Time) is used.
Anywhere else, time values are computed according to the time offset of your web client.)r9   rŽ   r–   Ú_compute_tz_offsetzTimezone offset)rÛ   r9   ú	res.usersÚSalespersonÚ_compute_user_idz,The internal user in charge of this contact.)r9   rÛ   Ú
precomputerÞ   rÜ   r–   r   Úuser_idúTax IDz�The Tax Identification Number. Values here will be validated based on the country format. You can use '/' to indicate that the partner is not subject to tax.)r9   r_   r–   zTax ID LabelÚ_compute_vat_label)r9   rÛ   zPartner with same Tax IDÚ_compute_same_vat_partner_id)r9   rÛ   rÜ   Úsame_vat_partner_idz"Partner with same Company RegistryÚ same_company_registry_partner_idú
Company IDÚ_compute_company_registryÚbtree_not_nullz†The registry number of the company. Use it if it is different from the Tax ID. It must be unique across all partners of a same country)r9   rÛ   rÜ   rÞ   r_   r–   zCompany ID LabelÚ_compute_company_registry_labelÚ%_compute_company_registry_placeholderzres.partner.bankr™   ÚBanksr”   r   Úbank_idszWebsite LinkÚNotesr…   r˜   ÚTags)r›   rœ   r9   rŽ   r„   ©rŽ   z.Check this box if this contact is an Employee.)r–   zJob Position))ÚcontactrÈ   )rÎ   ÚInvoice)rÏ   ÚDelivery)rÐ   ÚOtherzAddress Typerû   )r9   rŽ   zAddress Type DescriptionÚ_compute_type_address_label)Úchange_defaultúres.country.stateÚStateÚrestrictz"[('country_id', '=?', country_id)])r9   r’   r¹   r   r   zres.countryÚCountry)r9   r’   r   r   zcountry_id.codezCountry Code)rÝ   r9   zGeo Latitude)é
   é   )r9   ÚdigitszGeo LongitudezFormatted EmailÚ_compute_email_formattedz*Format email address "Name <email@domain>")rÛ   r–   zIs a Companyz;Check if the contact is a company, otherwise it is a personÚ_compute_is_public)rÛ   Úcompute_sudoúres.partner.industryÚIndustryÚResPartnerIndustryÚindustry_idzCompany Type)ÚpersonÚPerson)r<   ÚCompanyÚ_compute_company_typeÚ_write_company_type)r9   Ú	selectionrÛ   Úinverseúres.companyr  r—   r   rÓ   zColor Indexr   ÚUsers)r9   Úbypass_search_accessÚuser_idsz	Main UserÚ_compute_main_user_idz‹There can be several users related to the same partner. When a single user is needed, this field attempts to find the most appropriate one.)r9   rÛ   r–   Úmain_user_idzShare PartnerÚ_compute_partner_sharezŸEither customer (not a user), either shared user. Indicated the current partner is a customer without access or with a limited access created for sharing data.)rÛ   rÜ   r–   Ú_compute_contact_addresszComplete AddresszCommercial EntityÚ_compute_commercial_partner)r9   rÛ   rÜ   Ú	recursiver_   Úcommercial_partner_idzCompany Name EntityÚ _compute_commercial_company_name)rÛ   rÜ   zCompany Namez'Use a barcode to identify this contact.)r–   r�   Úcompany_dependentÚ_compute_get_ids)Úcomodel_namerÛ   r$   ÚStatsÚ_compute_application_statisticsc                 C  s&   |   ¡ }| D ]
}| |jg ¡|_qd S r2   )Ú$_compute_application_statistics_hookrk   rn   Úapplication_statistics)r$   ÚresultÚpr%   r%   r&   r&  ;  s   ÿz*ResPartner._compute_application_statisticsc                 C  ó   t tƒS )z¦ Hook for override, as overriding compute method does not update
        cache accordingly. All overrides receive False instead of previously
        assigned value. )r   Úlistr#   r%   r%   r&   r'  @  s   z/ResPartner._compute_application_statistics_hookzCCHECK( (type='contact' AND name IS NOT NULL) or (type!='contact') )zContacts require a namec                 C  s   |   ¡  t | jp
d¡S ©Nr¥   )Ú
ensure_oner
   Ústreet_splitr   r#   r%   r%   r&   Ú_get_street_splitK  s   zResPartner._get_street_splitr§   zuser_ids.shareÚ
image_1920Ú
is_companyrƒ   c                   ó   t ƒ  ¡  d S r2   )r:   Ú_compute_avatar_1920r#   rF   r%   r&   r4  O  r(   zResPartner._compute_avatar_1920Ú
image_1024c                   r3  r2   )r:   Ú_compute_avatar_1024r#   rF   r%   r&   r6  S  r(   zResPartner._compute_avatar_1024Ú	image_512c                   r3  r2   )r:   Ú_compute_avatar_512r#   rF   r%   r&   r8  W  r(   zResPartner._compute_avatar_512Ú	image_256c                   r3  r2   )r:   Ú_compute_avatar_256r#   rF   r%   r&   r:  [  r(   zResPartner._compute_avatar_256Ú	image_128c                   r3  r2   )r:   Ú_compute_avatar_128r#   rF   r%   r&   r<  _  r(   zResPartner._compute_avatar_128c           	        sš   |   dd„ ¡}tt|ƒ |ˆ ¡ | |   ‡ fdd„¡}tj|dd„ d�D ]\}}| jd j|Ž }t 	|d  
¡ ¡||< q$| | | D ]}|ˆ  ||< qBd S )Nc                 S  s   | j | j  d¡ p| jdkS )NÚsharerû   )r  Úfilteredrƒ   ©Úpartnerr%   r%   r&   r.   e  s    z,ResPartner._compute_avatar.<locals>.<lambda>c                   s
   | ˆ   S r2   r%   ©r*  ©Úimage_fieldr%   r&   r.   g  ó   
 c                 S  ó   |   ¡ S r2   )Ú_avatar_get_placeholder_pathrA  r%   r%   r&   r.   h  ó    r0   rc   r   )r>  r:   rž   Ú_compute_avatarr
   Úgroupbyr!   ÚconcatÚbase64Ú	b64encodeÚ_avatar_get_placeholder)	r$   Úavatar_fieldrC  Úpartners_with_internal_userÚpartners_without_imager   ÚgroupÚgroup_partnersr@  rF   rB  r&   rH  c  s   ÿÿzResPartner._compute_avatarc                   s>   | j rdS | jdkrdS | jdkrdS | jdkrdS tƒ  ¡ S )Nz!base/static/img/company_image.pngrÏ   zbase/static/img/truck.pngrÎ   zbase/static/img/bill.pngrÐ   zbase/static/img/puzzle.png)r2  rƒ   r:   rF  r#   rF   r%   r&   rF  o  s   



z'ResPartner._avatar_get_placeholder_pathc                 C  sŠ   |   ¡  | j}t| jd  | j¡ƒ}| jpd}| js| jrA|s)| j	|v r)|| j	 }| j
sA| jj d¡sA| jp;|  ¡ jj› d|› �}| ¡ S )Nrƒ   r¥   Ú!partner_display_name_hide_companyú, )r.  Ú_complete_name_displayed_typesÚdictrÕ   Ú_description_selectionr!   r§   Úcompany_namer“   rƒ   r2  rj   rk   Úcommercial_company_namerh   Ústrip)r$   Údisplayed_typesÚtype_descriptionr§   r%   r%   r&   Ú_get_complete_namez  s   

zResPartner._get_complete_namerX  rY  c                 C  s   | D ]
}|  i ¡ ¡ |_qd S r2   )rm   r]  rÉ   ©r$   r@  r%   r%   r&   rÚ   ˆ  ó   ÿz!ResPartner._compute_complete_namec                 C  s8   |   d¡D ]}|jjp|  dg¡ d¡p| jj|_qdS )z‹ While creating / updating child contact, take the parent lang by
        default if any. 0therwise, fallback to default context / DB lang r“   ÚlangN)r>  r“   r`  rÔ   rk   r!   r^  r%   r%   r&   rã   �  s   &ÿzResPartner._compute_langr`  c                 C  s&   t | jd  ¡ ƒ}| D ]}||_qd S r    )Úlenr!   r"   Úactive_lang_count)r$   Ú
lang_countr@  r%   r%   r&   rä   ”  s   ÿz%ResPartner._compute_active_lang_countr*   c                 C  s.   | D ]}t j  t |jpd¡¡ d¡|_qd S )NÚGMTz%z)ÚdatetimeÚnowÚpytzÚtimezoner*   ÚstrftimeÚ	tz_offsetr^  r%   r%   r&   ræ   š  s   "ÿzResPartner._compute_tz_offsetc                 C  s"   |   dd„ ¡D ]}|jj|_qdS )z: Synchronize sales rep with parent if partner is a person c                 S  s   | j  o| jdko| jj S )Nr  )rë   Úcompany_typer“   r?  r%   r%   r&   r.   ¢  s    z-ResPartner._compute_user_id.<locals>.<lambda>N)r>  r“   rë   r^  r%   r%   r&   ré   Ÿ  s   ÿzResPartner._compute_user_idÚuidzuser_ids.activec                 C  sŒ   | D ]A}| j jj|kr| j j|_q|j dd„ ¡ | jj¡}|s5|j| j d  	d¡kr5| j d  	d¡|_q|j
dd„ dd�d d	… |_qd S )
Nc                 S  s   | j S r2   )rÃ   ©Úur%   r%   r&   r.   ¬  s    z2ResPartner._compute_main_user_id.<locals>.<lambda>zir.model.datazbase.partner_rootzbase.user_rootc                 S  s   | j  | j fS r2   )r=  rn   rm  r%   r%   r&   r.   ²  s    T)Úreverser   )r!   Úuserr™   r  r  r>  Úwith_prefetchÚidsrn   Ú_xmlid_to_res_idr^   ©r$   r@  Úusersr%   r%   r&   r  ¥  s   
ÿþ÷z ResPartner._compute_main_user_idc                 C  sT   | j d  tj¡j}|| v rd|_| | D ]}|j p%tdd„ |jD ƒƒ |_qd S )Nrç   Fc                 s  s   � | ]}|j  V  qd S r2   )r=  ©r)   rp  r%   r%   r&   Ú	<genexpr>»  ó   € z4ResPartner._compute_partner_share.<locals>.<genexpr>)r!   rÑ   r   ÚSUPERUSER_IDr™   Úpartner_sharer  Úany)r$   Úsuper_partnerr@  r%   r%   r&   r  µ  s   "ÿz!ResPartner._compute_partner_sharerÌ   rÍ   c                 C  s–  | D ]Æ}|j j}| jdd� ¡ }|jg}|jot|jƒdk}|rX|jrXd|jjv rX|jd d…  ¡ r=| 	|jdd … ¡ n| 	|jj
|j ¡ t |jj
¡ }rX| 	||j ¡ dd|fg}|jrm|dd|jjdgfg7 }|jr||d	dd|jjgfg7 }|r‹|d
d|fdd
d|fg7 }|o—|j o—|j|dd�|_dd|jfd	dd|jjgfg}|r·|d
d|fdd
d|fg7 }t|jƒoÆ|j oÆ|j|dd�|_qd S )NF©rà   r   Ú	EU_PREFIXrX   rÌ   Úinr   rÓ   rn   z!=ú!r±   ©ÚlimitrÍ   rß   )Ú_originrn   rm   rh   rÌ   ra  r   Úcountry_group_codesÚisalphar¦   ÚcodeÚEU_EXTRA_VAT_CODESrk   rÓ   r“   Úsearchrï   rÍ   Úboolrð   )r$   r@  r™   rw   ÚvatsÚshould_check_vatÚnew_coder¹   r%   r%   r&   rî   ½  s6   ÿ
þ$Ýz'ResPartner._compute_same_vat_partner_idr<   c                 C  s   | j jjjp	tdƒ| _d S )Nrì   )r!   r<   r   r=   r   r#   r%   r%   r&   rí   ä  s   zResPartner._compute_vat_labelc                 C  s`   | D ]+}|j dkrtdƒ|_q|j dkrtdƒ|_q|j dkr(|jr(tdƒ|_qtdƒ|_qd S )NrÎ   zInvoice AddressrÏ   zDelivery Addressrû   zCompany AddressÚAddress)rƒ   r   Útype_address_labelr“   r^  r%   r%   r&   rÿ   è  s   

øz&ResPartner._compute_type_address_labelc                 C  rE  r2   )Ú_display_address_dependsr#   r%   r%   r&   r.   ô  rG  c                 C  s   | D ]}|  ¡ |_qd S r2   )Ú_display_addressÚcontact_addressr^  r%   r%   r&   r  ô  r¤   z#ResPartner._compute_contact_addressc                 C  s   | D ]}|j |_qd S r2   )rn   r$   r^  r%   r%   r&   r#  ù  s   
ÿzResPartner._compute_get_idszparent_id.commercial_partner_idc                 C  s,   | D ]}|j s
|js||_q|jj|_qd S r2   )r2  r“   r   r^  r%   r%   r&   r  ý  s
   üz&ResPartner._compute_commercial_partnerzparent_id.is_companyzcommercial_partner_id.namec                 C  s(   | D ]}|j }|jr|jp|j|_qd S r2   )r   r2  r§   rX  rY  )r$   r@  r*  r%   r%   r&   r!    s   þz+ResPartner._compute_commercial_company_namec                 C  s   | D ]}|j |_ qd S r2   )rÍ   )r$   r<   r%   r%   r&   rò     s   
ÿz$ResPartner._compute_company_registryc                 C  s0   |   ¡ }| D ]}|jj}| |tdƒ¡|_qd S )Nrñ   )Ú_get_company_registry_labelsr   r†  rk   r   Úcompany_registry_label)r$   Úlabel_by_countryr<   Úcountry_coder%   r%   r&   rô     s
   þz*ResPartner._compute_company_registry_labelc                 C  s   i S r2   r%   r#   r%   r%   r&   r’    r5   z'ResPartner._get_company_registry_labelsc                 C  s
   d| _ d S ©NF)Úcompany_registry_placeholderr#   r%   r%   r&   rõ     r‰   z0ResPartner._compute_company_registry_placeholderc                 C  r    )Nz0You cannot create recursive Partner hierarchies.r¡   r#   r%   r%   r&   r£     r¤   zResPartner._check_parent_idc                 C  sR   |   dd„ ¡}| jd  dd|jfgdg¡}|D ]}||jjkr&ttdƒƒ‚qdS )z·
        Check that for every partner which has a company,
        if there exists a company linked to that partner,
        the company_id set on the partner is that company
        c                 S  s   | j o| jS r2   )r2  rÓ   rA  r%   r%   r&   r.   )  s    z3ResPartner._check_partner_company.<locals>.<lambda>r  r™   r  zXThe company assigned to this partner does not match the company this partner represents.N)r>  r!   Úsearch_fetchrr  r™   rÓ   r   r   )r$   ÚpartnersÚ	companiesr<   r%   r%   r&   Ú_check_partner_company"  s   ÿÿz!ResPartner._check_partner_companyNc                   s@   t |pi ƒ}tƒ j|d�}| d¡r|S ‡ fdd„tˆ |ƒD ƒS )Nrú   r§   c                   s(   g | ]\}}t |ˆ j d |j¡d�‘qS )z	%s (copy))r§   )rV  r!   r   r§   )r)   r@  Úvalsr#   r%   r&   r+   4  ó   ( z(ResPartner.copy_data.<locals>.<listcomp>)rV  r:   Ú	copy_datark   r   )r$   rŽ   Ú	vals_listrF   r#   r&   rž  /  s
   
zResPartner.copy_datac                 C  s>   | j sd S i }| j}|jp| jdkr| j  ¡  }r||d< |S )Nrû   r¸   )r“   rƒ  rƒ   Ú_get_address_values)r$   r)  r@  Úaddress_valuesr%   r%   r&   Úonchange_parent_id6  s   zResPartner.onchange_parent_idc                 C  s&   | j r| j | jj krd| _d S d S d S r–  )r   r   r#   r%   r%   r&   Ú_onchange_country_idE  s   
ÿzResPartner._onchange_country_idc                 C  s,   | j jr| j| j jkr| j j| _d S d S d S r2   )r   r   r#   r%   r%   r&   Ú_onchange_stateJ  s   ÿzResPartner._onchange_statec                 C  s   | j r| j jj| _d S d S r2   )r“   rÓ   rn   r#   r%   r%   r&   Ú_onchange_company_idO  s   ÿzResPartner._onchange_company_idrÊ   c                 C  s`   d| _ | D ](}t |j¡}|rt |jpdd |¡f¡|_ q|jr-t |jp'd|jf¡|_ qdS )ae   Compute formatted email for partner, using formataddr. Be defensive
        in computation, notably

          * double format: if email already holds a formatted email like
            'Name' <email@domain.com> we should not use it as it to compute
            email formatted like "Name <'Name' <email@domain.com>>";
          * multi emails: sometimes this field is used to hold several addresses
            like email1@domain.com, email2@domain.com. We currently let this value
            untouched, but remove any formatting from multi emails;
          * invalid email: if something is wrong, keep it in email_formatted as
            this eases management and understanding of failures at mail.mail,
            mail.notification and mailing.trace level;
          * void email: email_formatted is False, as we cannot do anything with
            it;
        FÚFalseú,N)Úemail_formattedr
   Úemail_normalize_allrÊ   Ú
formataddrr§   r¨   )r$   r@  Úemails_normalizedr%   r%   r&   r  T  s   
þþ€öz#ResPartner._compute_email_formattedc                 C  s   | D ]
}|j r	dnd|_qd S )Nr<   r  )r2  rk  r^  r%   r%   r&   r  u  r_  z ResPartner._compute_company_typec                 C  s   | D ]}|j dk|_qd S ©Nr<   ©rk  r2  r^  r%   r%   r&   r  z  s   ÿzResPartner._write_company_typerk  c                 C  s   | j dk| _d S r¬  r­  r#   r%   r%   r&   Úonchange_company_type~  ó   z ResPartner.onchange_company_typeÚbarcodec                 C  s>   | D ]}|j r| jd  dd|j fg¡dkrttdƒƒ‚qd S )Nrc   r°  rß   r   z(Another partner already has this barcode)r°  r!   Úsearch_countr   r   r^  r%   r%   r&   Ú_check_barcode_unicity‚  s
   $€þz!ResPartner._check_barcode_unicityc                   s:   t ‡ fdd„|D ƒƒrttdƒƒ‚ˆ  ‡ fdd„|D ƒ¡S )zB Returns dict of write() values for synchronizing ``field_names`` c                 3  s    � | ]}ˆ j | jd kV  qdS )Úone2manyN)rÕ   rƒ   ©r)   Úfnamer#   r%   r&   rw  Š  s   € z7ResPartner._convert_fields_to_values.<locals>.<genexpr>zYOne2Many fields cannot be synchronized as part of `commercial_fields` or `address fields`c                   ó   i | ]}|ˆ | “qS r%   r%   r´  r#   r%   r&   Ú
<dictcomp>Œ  ó    z8ResPartner._convert_fields_to_values.<locals>.<dictcomp>)r{  ÚAssertionErrorr   Ú_convert_to_write)r$   Úfield_namesr%   r#   r&   Ú_convert_fields_to_valuesˆ  s   z$ResPartner._convert_fields_to_valuesc                 C  r+  )zCReturns the list of address fields that are synced from the parent.)r,  r]   r#   r%   r%   r&   Ú_address_fieldsŽ  ó   zResPartner._address_fieldsc                 C  rE  )z>Returns the list of address fields usable to format addresses.)r½  r#   r%   r%   r&   Ú_formatting_address_fields“  r¾  z%ResPartner._formatting_address_fieldsc                   s,   ˆ   ¡ }t‡ fdd„|D ƒƒrˆ  |¡S i S )z€ Get address values from record if at least one value is set. Otherwise
        it is considered empty and nothing is returned. c                 3  ó   � | ]}ˆ | V  qd S r2   r%   ©r)   r1   r#   r%   r&   rw  œ  rx  z1ResPartner._get_address_values.<locals>.<genexpr>)r½  r{  r¼  )r$   r`   r%   r#   r&   r   ˜  s   
zResPartner._get_address_valuesc                   s.   ‡ fdd„|   ¡ D ƒ}|rtƒ  |¡ dS dS )zÜ Filter values from vals that are liked to address definition, and
        update recordset using super().write to avoid loops and side effects
        due to synchronization of address fields through partner hierarchy. c                   s   i | ]}|ˆ v r|ˆ | “qS r%   r%   rÁ  ©rœ  r%   r&   r·  ¤  re   z.ResPartner._update_address.<locals>.<dictcomp>N)r½  r:   Úwrite)r$   rœ  Ú	addr_valsrF   rÂ  r&   Ú_update_address   s   ÿzResPartner._update_addressc                 C  s   |   ¡ ddg S )až   Returns the list of fields that are managed by the commercial entity
        to which a partner belongs. These fields are meant to be hidden on
        partners that aren't `commercial entities` themselves, or synchronized
        at update (if present in _synced_commercial_fields), and will be
        delegated to the parent `commercial entity`. The list is meant to be
        extended by inheriting classes. rÍ   r  )Ú_synced_commercial_fieldsr#   r%   r%   r&   Ú_commercial_fields¨  s   zResPartner._commercial_fieldsc                 C  s   dgS )zÁ Returns the list of fields that are managed by the commercial entity
        to which a partner belongs. When modified on a children, update is
        propagated until the commercial entity. rÌ   r%   r#   r%   r%   r&   rÆ  ²  s   z$ResPartner._synced_commercial_fieldsc                   ó(   ‡ fdd„ˆ   ¡ D ƒ}|rˆ  |¡S i S )z£ Get commercial values from record. Return only set values, as they
        are considered individually, and only set values should be taken into
        account. c                   ó   g | ]}ˆ | r|‘qS r%   r%   r´  r#   r%   r&   r+   ½  rT   z5ResPartner._get_commercial_values.<locals>.<listcomp>)rÇ  r¼  )r$   Úset_commercial_fieldsr%   r#   r&   Ú_get_commercial_values¹  s   
z!ResPartner._get_commercial_valuesc                   rÈ  )zp Get synchronized commercial values from ercord. Return only set values
        as for other commercial values. c                   rÉ  r%   r%   r´  r#   r%   r&   r+   Å  rT   z<ResPartner._get_synced_commercial_values.<locals>.<listcomp>)rÆ  r¼  )r$   Úset_synced_fieldsr%   r#   r&   Ú_get_synced_commercial_valuesÂ  s   
z(ResPartner._get_synced_commercial_valuesc                   s   ‡ fdd„ˆ   ¡ D ƒS )Nc                   s   g | ]
}ˆ j | jr|‘qS r%   )rÕ   r"  r´  r#   r%   r&   r+   Ì  s    
þÿzCResPartner._company_dependent_commercial_fields.<locals>.<listcomp>)rÇ  r#   r%   r#   r&   Ú$_company_dependent_commercial_fieldsÊ  s   
ÿz/ResPartner._company_dependent_commercial_fieldsc                 C  s<   | j }|| kr| ¡ }|r|  |¡ |  ¡  |  ¡  dS dS )zu Handle sync of commercial fields when a new parent commercial entity is set,
        as if they were related fields N)r   rË  rÃ  Ú_commercial_sync_to_descendantsÚ"_company_dependent_commercial_sync)r$   Úcommercial_partnerÚ	sync_valsr%   r%   r&   Ú_commercial_sync_from_companyÑ  s   
ûz(ResPartner._commercial_sync_from_companyc                 C  sX   |   ¡  }sdS | jd  ¡  g ¡D ]}|| jjkrq|  |¡}| |j |¡¡ qdS )zT Propagate sync of company dependant commercial fields to other
        commpanies. Nr  )	rÎ  r!   rh   rˆ  r<   Úwith_companyrÃ  r   r¼  )r$   Úfields_to_syncÚcompany_sudoÚself_in_companyr%   r%   r&   rÐ  Ü  s   

ÿüz-ResPartner._company_dependent_commercial_syncc                 C  sR   | j }|du r|  ¡ }| |¡}| j dd„ ¡}|D ]}| |¡ q| |¡ dS )z1 Handle sync of commercial fields to descendants Nc                 S  s   | j  S r2   ©r2  ©Úcr%   r%   r&   r.   ð  rG  z<ResPartner._commercial_sync_to_descendants.<locals>.<lambda>)r   rÇ  r¼  r•   r>  rÏ  rÃ  )r$   rÕ  rÑ  rÒ  Úsync_childrenÚchildr%   r%   r&   rÏ  ê  s   
z*ResPartner._commercial_sync_to_descendantsc                   s8  ˆ  d¡sˆ  d¡dkr+ˆ  d¡rˆ  ¡  ¡  ˆ jr+ˆ jdkr+ˆ j ¡  }r+ˆ  |¡ tˆ jƒoTtˆ jdkƒoTt‡fdd„ˆ  	¡ D ƒƒpGdˆv oTt‡ fdd„ˆ  	¡ D ƒƒ}|raˆ  ¡ }ˆ j 
|¡ tˆ jƒoˆˆ jˆ koˆt‡fdd„ˆ  ¡ D ƒƒp{dˆv oˆt‡ fdd„ˆ  ¡ D ƒƒ}|r•ˆ  ¡ }ˆ j 
|¡ ˆ  ˆ¡ d	S )
ap   Sync commercial fields and address fields from company and to children.
        Also synchronize address to parent. This somehow mimics related fields
        to the parent, with more control. This method should be called after
        updating values in cache e.g. self should contain new values.

        :param dict values: updated values, triggering sync
        r“   rƒ   rû   c                 3  ó   � | ]}|ˆ v V  qd S r2   r%   rR   ©r×   r%   r&   rw    rx  z*ResPartner._fields_sync.<locals>.<genexpr>c                 3  ó"   � | ]}ˆ | ˆ j | kV  qd S r2   ©r“   r´  r#   r%   r&   rw    ó   €  c                 3  rÝ  r2   r%   rR   rÞ  r%   r&   rw    rx  c                 3  rß  r2   rà  r´  r#   r%   r&   rw    rá  N)rk   rh   rÓ  r“   rƒ   r   rÅ  r‰  r{  r½  rÃ  r   rÆ  rÍ  Ú_children_sync)r$   r×   r¡  Úaddress_to_upstreamÚnew_addressÚcommercial_to_upstreamÚnew_synced_commercialsr%   ©r$   r×   r&   Ú_fields_syncõ  s.   	

 þú þúzResPartner._fields_syncc                   sr   | j sd S | j| krˆ  ¡ |  ¡ @ }|  ¡  |¡ |  ¡ }t‡ fdd„|D ƒƒr7| j  dd„ ¡}| 	ˆ ¡ d S d S )Nc                 3  rÝ  r2   r%   rR   rÞ  r%   r&   rw  +  rx  z,ResPartner._children_sync.<locals>.<genexpr>c                 S  s
   | j dkS )Nrû   )rƒ   rÙ  r%   r%   r&   r.   ,  rD  z+ResPartner._children_sync.<locals>.<lambda>)
r•   r   ÚkeysrÇ  rh   rÏ  r½  r{  r>  rÅ  )r$   r×   rÕ  r`   Úcontactsr%   rÞ  r&   râ  "  s   
þzResPartner._children_syncc                   s|   ˆj ‰ ˆ ¡ }ˆ jsˆ j s8t‡fdd„|D ƒƒr6t‡ fdd„|D ƒƒs:tˆ jƒdkr<ˆ |¡}ˆ  |¡ dS dS dS dS dS )zŠ On creation of first contact for a company (or root) that has no address, assume contact address
        was meant to be company address c                 3  rÀ  r2   r%   ©r)   Úfr#   r%   r&   rw  6  rx  z<ResPartner._handle_first_contact_creation.<locals>.<genexpr>c                 3  rÀ  r2   r%   rë  )rØ   r%   r&   rw  7  rx  r   N)r“   r½  r2  r{  ra  r•   r¼  rÅ  )r$   r`   rÄ  r%   )rØ   r$   r&   Ú_handle_first_contact_creation/  s   ÿÿþý
ùz)ResPartner._handle_first_contact_creationc                 C  s:   t  |¡}|js|js|j|jdd�}|jdd� ¡ }|S )Nr¥   )ÚnetlocÚpathÚhttp)Úscheme)r   Ú	url_parserñ  rî  rs   rï  Úto_url)r$   ÚwebsiteÚurlr%   r%   r&   Ú_clean_website=  s   
zResPartner._clean_websitec                 C  s4   | j dd�D ]}|j}|otdd„ |D ƒƒ|_qd S )NFr}  c                 s  s   � | ]}|  ¡ V  qd S r2   )Ú
_is_publicrv  r%   r%   r&   rw  H  rx  z0ResPartner._compute_is_public.<locals>.<genexpr>)rm   r  r{  Ú	is_publicrt  r%   r%   r&   r	  E  s   þzResPartner._compute_is_publicc                   s^  ˆ  d¡du rSˆ dg¡ ˆjd  ¡  ddˆjfg¡}|rSˆjd  d¡ d¡rCtdd	 d
d„ |D ƒ¡d�}| 	¡ }t
||tdƒƒ‚ttdd	 dd„ |D ƒ¡d�ƒ‚ˆ  d¡raˆ ˆd ¡ˆd< ˆ  d¡rjdˆd< ˆ  d¡r…ˆD ]‰ ˆ jD ]}|jˆ jkrƒˆd |_qvqq‡fdd„ˆD ƒ}dˆv rÏˆd }ˆD ]6‰ |rÃˆ jrÃˆjd  |¡}tdd„ ˆ jD ƒƒ}	t|	ƒdks»||	vrÃtˆj d¡ƒ‚ˆ jrÎˆ j d|i¡ q˜d}
dˆv ròˆjjsòˆjj d¡ròttˆ ¡ ƒ dˆ  d¡i¡}
ˆd= |
oùtƒ  ˆ¡}
tˆ|dd�D ]+\‰ ‰ˆ j ‡fdd „¡ }�r| d¡ ‡ ‡fd!d"„ˆ ¡ D ƒ}|�r+ˆ   |¡ �q|
S )#NrÃ   Fr  rç   r™   r  rÃ  z‡You cannot archive contacts linked to an active user.
You first need to archive their associated user.

Linked active users : %(names)srT  c                 S  ó   g | ]}|j ‘qS r%   ©rª   ©r)   rn  r%   r%   r&   r+   Z  r/   z$ResPartner.write.<locals>.<listcomp>©r¬   úGo to usersz“You cannot archive contacts linked to an active user.
Ask an administrator to archive their associated user first.

Linked active users :
%(names)sc                 S  rù  r%   rú  rû  r%   r%   r&   r+   `  r/   rô  r“   rX  r§   c                   s   g | ]‰ ‡ fd d„ˆD ƒ‘qS )c                   r¶  r%   r%   r´  r?  r%   r&   r·  p  r¸  z/ResPartner.write.<locals>.<listcomp>.<dictcomp>r%   )r)   rÂ  r?  r&   r+   p  re   rÓ   r  c                 s  s   � | ]}|j V  qd S r2   )rÓ   rv  r%   r%   r&   rw  |  s   € z#ResPartner.write.<locals>.<genexpr>r   zPThe selected company is not compatible with the companies of the related user(s)Tr2  zbase.group_partner_manager)Ústrictc                   s   |   ¡ o	| ˆ jjkS r2   )Ú_is_internalr!   rp  rm  r#   r%   r&   r.   ‰  r,   z"ResPartner.write.<locals>.<lambda>c                   s(   i | ]\}}ˆ | ˆ  |¡kr||“qS r%   ©rk   )r)   rµ  Úfvalue)r@  Ú
pre_valuesr%   r&   r·  ‹  r�  z$ResPartner.write.<locals>.<dictcomp>)!rk   Úinvalidate_recordsetr!   rh   rˆ  rr  Ú
has_accessr   r¨   Ú_action_showr   r   rö  r÷   Úacc_holder_namer§   r  rÑ   r?   ra  r   r•   rÃ  Úsurp  Ú	has_groupr:   rž   r   r>  Úcheck_accessÚitemsrè  )r$   rœ  ru  Ú	error_msgÚaction_errorÚbankÚpre_values_listrÓ   r<   rš  r)  Úinternal_usersÚupdatedrF   )r@  r  r$   rœ  r&   rÃ  J  sf   	þþ




€þ	

ÿ€

€zResPartner.writec                   sÊ   | j j d¡r|  |¡ |D ]}| d¡r|  |d ¡|d< | d¡r'd|d< qtƒ  |¡}t||ƒD ]\}}d|vrB|jrB| 	¡  q3| j j d¡rL|S t||ƒD ]\}}| j d  
|¡}| |¡ qQ|S )	NÚimport_filerô  r“   FrX  r`  Ú_partners_skip_fields_syncrc   )r!   rj   rk   Ú_check_import_consistencyrö  r:   Úcreater   r“   rã   Ú_add_missing_default_valuesrè  )r$   rŸ  rœ  r™  r@  r×   rF   r%   r&   r  �  s&   


€€zResPartner.create)Úat_uninstallc                 C  s�   | j d  ¡  dd| jfg¡}|sd S | j d  d¡ d¡r8tdd dd	„ |D ƒ¡d
�}| ¡ }t||tdƒƒ‚t	tdd dd	„ |D ƒ¡d
�ƒ‚)Nrç   r™   r  FrÃ  z›You cannot delete contacts linked to an active user.
You should rather archive them after archiving their associated user.

Linked active users : %(names)srT  c                 S  rù  r%   rú  rû  r%   r%   r&   r+   °  r/   z2ResPartner._unlink_except_user.<locals>.<listcomp>rü  rý  z’You cannot delete contacts linked to an active user.
Ask an administrator to archive their associated user first.

Linked active users :
%(names)sc                 S  rù  r%   rú  rû  r%   r%   r&   r+   ¶  r/   )
r!   rh   rˆ  rr  r  r   r¨   r  r   r   )r$   ru  r  r  r%   r%   r&   Ú_unlink_except_user¨  s   þþzResPartner._unlink_except_userc                   s<  t t| jdd�ƒ |¡}t t¡}t||ƒD ],\}}d }| d¡r*|j	|kr*|j	j
}d }|jr8|jdkr8|jj
}|||f  |j
¡ q| ¡ D ]A\\}}}i }	|r[|  |¡ |  ¡ ¡}	|r||  |¡}
|  ¡ D ]}|
| }|r{t|tjƒrw|j
n||	|< qf|	rˆ|  ¡  |¡ |	¡ qGt||ƒD ]\}}| |¡ | ¡  qŽ|S )NT)r  r“   rû   )r:   rž   rm   Ú_load_records_createÚcollectionsr   r,  r   rk   r   rn   r“   rƒ   r¦   r
  rÑ   r¼  rÇ  r½  Ú
isinstancer	   Ú	BaseModelrh   rÃ  râ  rí  )r$   rŸ  r™  Úgroupsr@  rœ  Úcp_idÚadd_idÚchildrenÚto_writerØ   rì  ÚvrF   r%   r&   r  ¸  s8   

€€

zResPartner._load_records_createc                   s<   |   ¡  |  ¡  ‰ r|  ˆ j‡ fdd„| jjD ƒdœ¡ dS )Nc                   s    g | ]}t  |tˆ jd �¡‘qS )rà  )r   ÚupdaterV  rn   )r)   r™   ©Únew_companyr%   r&   r+   ä  r\   z-ResPartner.create_company.<locals>.<listcomp>)r“   r•   T)r.  Ú_create_contact_parent_companyrÃ  rn   r•   rr  r#   r%   r#  r&   Úcreate_companyÞ  s   þzResPartner.create_companyc                 C  sF   |   ¡  | jrt| jd| jd�}| |  |  ¡ ¡¡ |  |¡S |  ¡ S )NT)r§   r2  rÌ   )	r.  rX  rV  rÌ   r"  r¼  r½  r  rÑ   rç  r%   r%   r&   r%  è  s   
z)ResPartner._create_contact_parent_companyc                 C  s   |   ¡  ddd| jjddœS )zF Utility method used to add an "Open Company" button in partner views zir.actions.act_windowrc   r8   r­   )rƒ   Ú	res_modelÚ	view_modeÚres_idÚtarget)r.  r   rn   r#   r%   r%   r&   Úopen_commercial_entityñ  s   üz!ResPartner.open_commercial_entityrÉ   Úshow_addressÚpartner_show_db_idÚ
show_emailÚshow_vatÚformatted_display_namec                 C  s”  t | jd  | j¡ƒ}| D ]º}|jj d¡r[|jpd}|js!|jr6|jp'|jj› d|jp2| |j	d¡› d�}|jj d¡rJ|j
rJ|› d|j
› d�}nq|jj d¡rZ|› d|j› d�}n`|j| jjd� ¡ }|jj d¡ru|› d	|j› d
�}|jj d¡rˆ|j
rˆ|› d|j
› d�}|jj d¡r™|d |jdd� }|jj d¡r»|jr»|jj d¡r³|› d|j› �}n|› d|j› �}t dd|¡}| ¡ |_qd S )Nrƒ   r0  r¥   z 	 --z--r.  r-  )r`  z (ú)z <Ú>r,  rf   T)Úwithout_companyr/  z 
 z - z\s+\n)rV  rÕ   rW  r!   rj   rk   r§   r“   rX  rƒ   rÊ   rn   rm   r`  r]  r�  rÌ   ÚreÚsubrZ  rª   )r$   r\  r@  r§   r%   r%   r&   r®   û  s6   
ÿ€ãz ResPartner._compute_display_namec                 C  s¤   | j j d¡}|r$|| jd  | j ¡vr$t| j jƒ}| d¡ |  |¡} t 	|¡\}}| j j d¡r:|s:t
tdƒƒ‚| j|p?|i}|rG||d< |  |¡}|j|jfS )at   Override of orm's name_create method for partners. The purpose is
            to handle some basic formats to create partners using the
            name_create.
            If only an email address is received and that the regex cannot find
            a name, the name will have the email value.
            If 'force_email' key in context: must find the email address. Údefault_typerƒ   Úforce_emailz.Couldn't create contact without email address!rÊ   )r!   rj   rk   rÕ   rÖ   rV  Úpoprm   r
   Úparse_contact_from_emailr   r   Ú	_rec_namer  rn   rª   )r$   r§   r6  rj   Úemail_normalizedÚcreate_valuesr@  r%   r%   r&   Úname_create!  s   


zResPartner.name_createc                 C  sx   |st tdƒƒ‚t |¡\}}|s|rt tdƒƒ‚|r*| jdd|fgdd�}|r*|S | j|p/|i}|r7||d< |  |¡S )ai   Find a partner with the given ``email`` or use :meth:`name_create`
        to create a new one.

        :param str email: email-like string, which should contain at least one email,
            e.g. ``"Raoul Grosbedon <r.g@grosbedon.fr>"``
        :param bool assert_valid_email: raise if no valid email is found
        :return: newly created record
        z/An email is required for find_or_create to workz>A valid email is required for find_or_create to work properly.rÊ   z=iliker   r�  )rp   r   r
   r9  rˆ  r:  r  )r$   rÊ   Úassert_valid_emailÚparsed_nameÚparsed_email_normalizedr™  r<  r%   r%   r&   Úfind_or_create8  s   

zResPartner.find_or_createc           	        sø   t |pg ƒ}d|vr| d¡ i }t ƒ ‰ | D ]L}|}|rb|g}|rV| d¡}ˆ  |¡ |j|v r<| |j¡s<|j||j< t|ƒt|ƒkrH|  S ‡ fdd„|jD ƒ| }|s!|js\|j	s]n|j	}|sq| d| jpjd¡}|D ]}| |¡pv|||< qn|S )a¶   Find contacts/addresses of the right type(s) by doing a depth-first-search
        through descendants within company boundaries (stop at entities flagged ``is_company``)
        then continuing the search at the ancestors that are within the same company boundaries.
        Defaults to partners of type ``'default'`` when the exact type is not found, or to the
        provided partner itself if no type ``'default'`` is found either. rû   r   c                   s   g | ]}|ˆ vr|j s|‘qS r%   rØ  ©r)   rÚ  ©Úvisitedr%   r&   r+   j  s    ÿÿz*ResPartner.address_get.<locals>.<listcomp>F)
r?   Úaddr8  rƒ   rk   rn   ra  r•   r2  r“   )	r$   Úadr_prefr)  r@  Úcurrent_partnerÚto_scanÚrecordrŽ   Úadr_typer%   rC  r&   Úaddress_getS  s:   


þùï€zResPartner.address_getc                   s>   | j j d¡rtd| j d  | j jd ¡jd�S tƒ  ||¡S )Nr˜   zPartners: %(category)sr…   )r«   )r!   rj   rk   r   rÑ   r§   r:   Úview_header_get)r$   r@   rA   rF   r%   r&   rL  y  s   þzResPartner.view_header_getc                 C  s   dS )NzG%(street)s
%(street2)s
%(city)s %(state_code)s %(zip)s
%(country_name)sr%   r#   r%   r%   r&   Ú_get_default_address_format‚  s   z&ResPartner._get_default_address_formatc                 C  s   | j jp|  ¡ S r2   )r   ri   rM  r#   r%   r%   r&   Ú_get_address_format†  r¯  zResPartner._get_address_formatc                 C  sˆ   |   ¡ }tt| jjpd| jjpd| jjpd|  ¡ | jpddœƒ}|  	¡ D ]
}| | p+d||< q$|r9d|d< ||fS | jr@d| }||fS )Nr¥   )rV   rW   r•  Úcountry_namerX  rX  z%(company_name)s
)
rN  r   Ústrr   r†  r§   r   Ú_get_country_namerY  r¿  )r$   r3  ri   ÚargsrS   r%   r%   r&   Ú_prepare_display_addressŠ  s    


ûþz#ResPartner._prepare_display_addressc                 C  s   |   |¡\}}|| S )aƒ  
        The purpose of this function is to build and return an address formatted accordingly to the
        standards of the country where it belongs.

        :param without_company: if address contains company
        :returns: the address formatted in a display that fit its country habits (or the default ones
            if not country is specified)
        :rtype: string
        )rS  )r$   r3  ri   rR  r%   r%   r&   r�  �  s   
zResPartner._display_addressc                 C  s   |   ¡ g d¢ S )N)r   rX  r   )r¿  r#   r%   r%   r&   r�  ª  r¯  z#ResPartner._display_address_dependsc                 C  s   t dƒddœgS )NzImport Template for Contactsz./base/static/xls/contacts_import_template.xlsx)ÚlabelÚtemplate)r   r#   r%   r%   r&   Úget_import_templates°  s   þzResPartner.get_import_templatesc                   s¨   | j d }dd„ |D ƒ}| ddt|ƒfgdg¡}|D ]6‰ ˆ  d¡rQt‡ fdd	„|D ƒƒ}| ˆ d ¡}|jj|krQd
d|jfdd|fg}|j	|dd�}|jˆ d< qdS )a)  
        The values created by an import are generated by a name search, field by field.
        As a result there is no check that the field values are consistent with each others.
        We check that if the state is given a value, it does belong to the given country, or we remove it.
        r  c                 S  s   h | ]}|  d ¡r|d  ’qS )r   r   )r)   rœ  r%   r%   r&   Ú	<setcomp>¿  re   z7ResPartner._check_import_consistency.<locals>.<setcomp>rn   r  r   r   c                 3  s.   � | ]}|d  ˆ   d¡kr|d d V  qdS )rn   r   r   r   Nr   rB  rÂ  r%   r&   rw  Ã  s   €, z7ResPartner._check_import_consistency.<locals>.<genexpr>r†  rß   r   r�  N)
r!   Úsearch_readr,  rk   ÚnextrÑ   r   rn   r†  rˆ  )r$   rŸ  ÚStatesÚ
states_idsÚstate_to_countryr   ÚstateÚstate_domainr%   rÂ  r&   r  ·  s   


ÿ
€øz$ResPartner._check_import_consistencyc                 C  s   | j jpdS r-  )r   r§   r#   r%   r%   r&   rQ  Ë  s   zResPartner._get_country_namec                 C  s&   |   ¡  | j| j| j| j| jjdœgS )N)Úcontact_typer   r   r   Úcountry)r.  r   r   r   r   r†  r#   r%   r%   r&   Ú_get_all_addrÎ  s   ûzResPartner._get_all_addrr2   )F)°rI   rJ   rK   rL   rM   Ú_inheritrº   Ú_rec_names_searchÚ_allow_sudo_commandsÚ_check_company_autor	   Úcheck_company_domain_parent_ofÚ_check_company_domainrU  rÒ   r   rN   rÔ   r   r¼   r§   rÉ   r¿   r“   rÀ   Úparent_namerÁ   r•   rË   Ú	Selectionr'   r`  r½   rb  r3   r*   rj  rë   rÌ   r=   rï   rð   rÍ   r“  r—  r÷   rô  ÚHtmlÚcommentrÅ   r˜   rÂ   rÃ   ÚemployeeÚfunctionrƒ   rŽ  r   r   r   r   r   r   r•  ÚFloatÚpartner_latitudeÚpartner_longituderÊ   r¨  Úphoner2  rø  r  rk  rÓ   r¾   r  r  rz  r‘  r   rY  rX  r°  r$   ÚJsonr(  r&  r'  Ú
ConstraintÚ_check_namer0  rÇ   r4  r6  r8  r:  r<  rH  rF  r]  rÚ   rã   rä   ræ   ré   Údepends_contextr  r  rî   rí   rÿ   r  r#  r  r!  rò   rô   r’  rõ   rÆ   r£   r›  rž  Úonchanger¢  r£  r¤  r¥  r  r  r  r®  r²  r¼  r½  r¿  r   rÅ  rÇ  rÆ  rË  rÍ  rÎ  rÓ  rÐ  rÏ  rè  râ  rí  rö  r	  rÃ  Úmodel_create_multir  r’   r  r  r&  r%  r+  r®   r=  rA  rK  rL  rM  rN  rS  r�  r�  rV  r  rQ  ra  rO   r%   r%   rF   r&   rž   ¸   sä  
 "þÿûÿ
ÿúþÿþüþýÿ
þ








&











 

		-F&
	
þ!&rž   c                   @  sB   e Zd ZdZdZdZejddd�Zejddd�Z	ej
ddd	�Zd
S )r  r  r  r†   rŠ   T)rŒ   z	Full NameÚActiverú   N)rI   rJ   rK   rL   rM   rº   r   r¼   r§   Ú	full_namerÂ   rÃ   r%   r%   r%   r&   r  Ù  s    r  )1Ú
__future__r   rK  r  re  rg  r4  r   Úrandomr   Úwerkzeugr   Úodoor   r   r	   r
   r   r   Úodoo.exceptionsr   r   r   ÚtypingÚTYPE_CHECKINGÚ	res_usersr   Úres_bankr   Úres_countryr   r   Úres_companyr   r]   r‡  rN   r'   r^   Úall_timezonesr3   r4   ÚAbstractModelr6   rP   ÚModelr„   rž   r  r%   r%   r%   r&   Ú<module>   sL    þ
N-        )