
    Ti&                     V   d Z ddlZddlmZ dee   dee   fdZdee   dee   fdZdee   defd	Zd
ee   dee   fdZ	d
ee   defdZ
dee   dee   fdZdee   dee   fdZdee   dee   fdZdee   defdZdee   dee   defdZdedefdZdedeeee   f   fdZy)zA
Data sanitization and validation utilities for Vera Medical CRM
    N)Optionalphonereturnc                     | syt        j                  dd|       }t        |      dk(  rd|dd  d|dd  d	|dd  S t        |      d
k(  r|d   dk(  rd|dd  d|dd  d	|dd  S | j                         S )zx
    Sanitize and format phone number
    Accepts various formats and returns (XXX) XXX-XXXX or original if invalid
    Nz\D 
   (   z)    -   r   1z+1 (         )resublenstrip)r   digitss     (/home/ab5.sw7ft.com/public_html/utils.pysanitize_phoner      s    
  VVE2u%F 6{b6"1:,b!Qvabzl;; 6{bVAY#-fQqk]"VAa[M6!":,?? ;;=    postal_codec                    | sy| j                  dd      j                  dd      j                         }t        |      dk\  rCt        |dd       }dD ]  }|t        |      k  s||   dk(  sd||<   ! dj	                  |      }t        |      dk(  r#t        j                  d	|      r|dd
  d|d
d  S t        |      dkD  r(|dd }t        j                  d	|      r|dd
  d|d
d  S | j                         S )z
    Sanitize and format Canadian postal code
    Accepts various formats and returns A1A 1A1 format
    Tries to fix common issues like 'O' instead of '0', extra characters, etc.
    N r   r   r   )r   r
      O0^[A-Z]\d[A-Z]\d[A-Z]\d$r
   )replaceupperr   listjoinr   matchr   )r   cleanedfixedis       r   sanitize_postal_coder)   '   s     !!#r*223;AACG 7|qWRa[! 	A3u:~%(c/a	 ''%. 7|qRXX&@'J"1+a}-- 7|a"1+88.8bqk]!GABK=11 r   c                     | sy| j                  dd      j                  dd      j                         }t        t        j                  d|            S )z$Validate Canadian postal code formatTr   r   r   r    )r!   r"   boolr   r%   )r   r&   s     r   validate_postal_coder,   K   sG    !!#r*223;AACG3W=>>r   emailc                 ~    | sy| j                         j                         } d| v rd| j                  d      d   v r| S y)zL
    Sanitize email address
    Returns lowercase trimmed email or None
    N@.r   )r   lowersplit)r-   s    r   sanitize_emailr3   X   sD    
 KKM!E e|u{{3/22r   c                 J    | syd}t        t        j                  ||             S )zValidate email formatTz0^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)r+   r   r%   )r-   patterns     r   validate_emailr6   i   s&     BG%())r   namec                 |   | sy| j                         } g d}| j                         }g }t        |      D ]  \  }}|dk(  r |j                  |j	                                +|j                         |v r |j                  |j                                ]d|v r9|j                  d      }|j                  dj                  d |D                     d|v r9|j                  d      }|j                  dj                  d |D                     |j                  |j	                                 dj                  |      S )	zZ
    Sanitize person name
    Capitalizes first letter of each word, handles prefixes
    N)vanvondedeldadir   r   c              3   <   K   | ]  }|j                           y wN
capitalize.0ps     r   	<genexpr>z sanitize_name.<locals>.<genexpr>        'F1'F   'c              3   <   K   | ]  }|j                           y wr@   rA   rC   s     r   rF   z sanitize_name.<locals>.<genexpr>   rG   rH   r   )r   r2   	enumerateappendrB   r1   r$   )r7   prefixeswordscapitalizedr(   wordpartss          r   sanitize_namerR   w   s
   
 ::<D 7HJJLEKU# 246t01ZZ\X%tzz|,D[JJsOEsxx'F'FFGD[JJsOEsxx'F'FFGt01!2$ 88K  r   c                 b    | sydj                  | j                               j                         S )zQ
    Sanitize company name
    Preserves capitalization but trims whitespace
    Nr   r$   r2   r   )r7   s    r   sanitize_company_namerU      s(    
 88DJJL!''))r   textc                 n    | sydj                  | j                               } | r| j                         S dS )zN
    Sanitize general text fields
    Removes excessive whitespace, trims
    Nr   rT   )rV   s    r   sanitize_textrX      s3    
  88DJJL!D4::<)T)r   c                 V    | syt        j                  dd| j                               }|S )zb
    Normalize text for fuzzy matching
    Removes spaces, punctuation, converts to lowercase
    r   z	[^a-z0-9])r   r   r1   )rV   
normalizeds     r   normalize_for_comparisonr[      s*    
  b$**,7Jr   str1str2c                    | r|syt        |       }t        |      }||k(  ryt        |      dk(  st        |      dk(  ry||v s||v rAt        t        |      t        |            }t        t        |      t        |            }||z  S t	        |      }t	        |      }t        ||z        }t        ||z        }	|	dkD  r||	z  S dS )zp
    Calculate similarity score between two strings (0.0 to 1.0)
    Uses simple character-based comparison
    g        g      ?r   )r[   r   minmaxset)
r\   r]   norm1norm2shorterlongerset1set2intersectionunions
             r   fuzzy_match_scorerj      s    
 t$T*E$T*E~ 5zQ#e*/ ~%c%j#e*-SZU, u:Du:Dtd{#LtE#(19<%5#5r   datac                    i }| j                         D ]R  \  }| t        |t              r|j                         sd|<   /dj	                         v rt        |      |<   Pdj	                         v rt        |      |<   qdj	                         v rt        |      |<   t        fddD              r!dj	                         vrt        |      |<   dj	                         v r!dj	                         v rt        |      |<   d	j	                         v r"dj	                         v rt        |      |<   .t        |t              rt        |      |<   N||<   U |S )
zU
    Sanitize all form data based on field type
    Returns sanitized dictionary
    Nr   r-   postalc              3   B   K   | ]  }|j                         v   y wr@   )r1   )rD   xkeys     r   rF   z%sanitize_form_data.<locals>.<genexpr>  s     Gaciik!Gs   )
first_name	last_namecompanyr7   firm)items
isinstancestrr   r1   r   r3   r)   anyrR   rU   rX   )rk   	sanitizedvaluerp   s      @r   sanitize_form_datar{      sT   
 Ijjl ##
U=Zs3EKKM!IcN ciik!+E2IcN 		#+E2IcN $1%8IcN G+FGGI]`]f]f]hLh*51IcN #))+%&CIIK*?259IcN syy{"v'<259IcN s#*51IcN #IcNG##J r   c                    g }g }| j                         D ]Z  \  }}d|j                         v r!|rt        |      s|j                  d|        d|j                         v sL|sOt	        |      r[\ t        |      dk(  |fS )z
    Validate form data
    Returns (is_valid, list_of_errors)
    Note: Postal codes are validated but don't block form submission (non-blocking)
    r-   zInvalid email format: rm   r   )ru   r1   r6   rL   r,   r   )rk   errorswarningsrp   rz   s        r   validate_form_datar   $  s     FH jjl 

Uciik!e!%( 6se<= syy{"u'. 
 K1f%%r   )__doc__r   typingr   rw   r   r)   r+   r,   r3   r6   rR   rU   rX   r[   floatrj   dictr{   tupler#   r    r   r   <module>r      sR   
 (3- HSM 6!hsm ! !H?hsm ? ?(3- HSM "*(3- *D *"! "!(3- "!J* *(3- ** *(3- *$8C= S 6HSM 6# 65 6L,T ,d ,f&T &eD$s)O&< &r   