
    =jo                       U d Z ddlmZ ddlZg  ej                  dej
                        df ej                  dej
                        df ej                  dej
                        d	f ej                  d
ej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  dej
                        df ej                  d ej
                        d!f ej                  d"ej
                        d#f ej                  d$ej
                        d%f ej                  d&ej
                        d'f ej                  d(ej
                        d)f ej                  d*ej
                        d+f ej                  d,ej
                        d-f ej                  d.ej
                        d/f ej                  d0ej
                        d1f ej                  d2ej
                        d3f ej                  d4ej
                        d5f ej                  d6ej
                        d7f ej                  d8ej
                        d9f ej                  d:ej
                        d;f ej                  d<ej
                        d=f ej                  d>ej
                        d?f ej                  d@ej
                        dAf ej                  dBej
                        dCf ej                  dDej
                        dEf ej                  dFej
                        dGf ej                  dHej
                        dIf ej                  dJej
                        dKf ej                  dLej
                        dMf ej                  dNej
                        dOf ej                  dPej
                        dQf ej                  dRej
                        dSf ej                  dTej
                        dUf ej                  dVej
                        dWf ej                  dXej
                        dYf ej                  dZej
                        d[f ej                  d\ej
                        d]f ej                  d^ej
                        df ej                  d_ej
                        df ej                  d`ej
                        dfZdaedb<    ej                  dc       ej                  dd       ej                  de       ej                  df       ej                  dg       ej                  dh      gZdiedj<   dndkZ	dodlZ
dpdmZy)qu   
Merchant name normalizer — Story 9.3.

Cleans raw statement strings using a built-in normalization table,
then falls back to regex heuristics.

Example: "AMZN*MARKETPLACE 04/22" → "Amazon"
         "SQ *COFFEE SHOP 123456" → "Coffee Shop"
    )annotationsNz:AMZN\*|AMAZON\s*MKTPL\*|AMAZON\s*MARKETPLACE|AMAZON\.COM\*Amazonz!AMAZON\s*PRIME\*|AMAZON\s*PRIME\bzAmazon PrimezAMAZON\s*WEB\s*SERVICES|AWSAWSzAMAZON\.COM\s+Amzn\.comzAMAZON\.COMz,APPLE\.COM/BILL|APPLE\s+ITUNES|APPLE\s+STOREApplezNETFLIX\.COM|NETFLIXNetflixzSPOTIFY\s*USA|SPOTIFYSpotifyzHULU\.COM|HULUHuluzDISNEY\+|DISNEY\s*PLUSzDisney+z"YOUTUBE\s*PREMIUM|GOOGLE\s*YOUTUBEzYouTube Premiumz$GOOGLE\s*\*GSUITE|GOOGLE\s*WORKSPACEzGoogle Workspacez
\bGOOGLE\bGooglez#MICROSOFT\s*\*|MICROSOFT\s*365|MSFT	MicrosoftzPAYPAL\s*\*PayPalVENMOVenmozUBER\s*\*EATS|UBEREATSz	Uber EatszUBER\s*\*TRIP|UBER\bUberz	LYFT\s*\*LyftzDOORDASH\*|DOORDASHDoorDashzGRUBHUB\*|GRUBHUBGrubhubzINSTACART\*|INSTACART	InstacartzWALMART(?:\s*\.COM)?Walmartz TARGET\s*(?:\.COM)?(?:\s*T-\d+)?TargetzCOSTCO\s*WHSE|COSTCOCostcozWHOLE\s*FOODS\s*MARKET?zWhole FoodszTRADER\s*JOEzTrader Joe'sKROGERKrogerz\bALDI\bAldi	STARBUCKS	StarbuckszDUNKIN|DUNKIN'\s*DONUTSzDunkin'zMCDONALD'?S|MCDONALDSz
McDonald'szCHICK-FIL-A|CHICKFILAzChick-fil-ACHIPOTLEChipotlezSUBWAY\bSubwayzCVS\s*PHARMACY|CVS\s*\d+zCVS PharmacyzWALGREEN|WALGREENS	Walgreensz
RITE\s*AIDzRite Aidz
BEST\s*BUYzBest BuyzTHE\s+HOME\s+DEPOT|HOME\s*DEPOTz
Home DepotzLOWE'?S|LOWES\s+#zLowe'sz\bKOHL'?S\b|\bKOHLS\bzKohl'szSHELL\s*OIL|SHELL\s*\d+ShellzBP\s*#\d+|BP\s*GASBPzEXXON\s*MOBIL|EXXON
ExxonMobilzCHEVRON\s+\d+|CHEVRONChevronz2SQ\s*\*([^#]+?)(?:\s+\d|\s{2,}|\s*-\s*[A-Z]{2,}|$)zTST\*\s*(.+?)\s+-\s+[A-Z]zTST\*\s*(.+)zlist[tuple[re.Pattern, str]]_BUILTIN_RULESz\s+\d{2}/\d{2}(?:/\d{2,4})?$z
\s+\d{4,}$z#\s*\d+\s*$z\s+[A-Z]{2}$\s{2,}z	^\s+|\s+$zlist[re.Pattern]_STRIP_PATTERNSc                   | s| S | j                         }t        D ]X  \  }}|j                  |      }|s||c S |j                  r|j	                  d      j                         n|}t        |      c S  t        |      S )z
    Normalize a raw merchant string to a clean display name.

    1. Check built-in rules (first match wins)
    2. Apply regex heuristics to strip noise
    3. Title-case the result
       )stripr$   search	lastindexgroup_clean_heuristics)rawraw_strippedpattern
normalizedmcaptureds         </var/www/html/financials/app/services/merchant_normalizer.py	normalizer5   Q   s     
99;L  . /NN<(%!!-.[[qwwqz'')lH$X../ \**    c                ~    | }t         D ]  }|j                  d |      } |j                         j                         S )z*Apply stripping heuristics and title-case.c                <    | j                   j                  dk(  rdS dS )Nr%     )rer0   )r2   s    r4   <lambda>z#_clean_heuristics.<locals>.<lambda>p   s    addlli.Gs R r6   )r&   subr)   title)textresultr0   s      r4   r-   r-   l   s?    F" YOQWXY<<>!!r6   c                    | j                         }|D ]=  }|j                  dd      }|s|j                         |v s+|j                  dd      c S  y)z
    Check user-confirmed MerchantMapping records against raw merchant string.

    user_mappings: list of dicts with 'raw_pattern' and 'normalized' keys
    Returns normalized name if a user mapping matches, else None.
    raw_patternr:   r1   N)upperget)r.   user_mappings	raw_uppermappingr0   s        r4   apply_user_mappingsrH   t   sT     		I  1++mR0w}})3;;|R001 r6   )r.   strreturnrI   )r?   rI   rJ   rI   )r.   rI   rE   z
list[dict]rJ   z
str | None)__doc__
__future__r   r;   compileIr$   __annotations__r&   r5   r-   rH    r6   r4   <module>rQ      s   # 	40RZZMrttTV^_40RZZ4bdd;NS40 RZZ.5UK40 RZZ*BDD1XN	40
 RZZ%hO40 RZZ?FP40 RZZ'.YO40 RZZ("$$/YO40 RZZ!244(VL40 RZZ)2440YO40 RZZ5rtt<EVW40 RZZ7>EWX40 RZZrtt$XN40 RZZ6=[Q40 RZZ%XN40  RZZ"$$WM!40" RZZ)2440[Q#40$ RZZ'.VL%40& RZZbdd#VL'40( RZZ&-ZP)40* RZZ$bdd+YO+40, RZZ("$$/[Q-40. RZZ'.YO/400 RZZ3RTT:HM1402 RZZ'.XN3404 RZZ*BDD1]S5406 RZZ&^T7408 RZZ	244 XN940: RZZRTT"VL;40< RZZbdd#[Q=40> RZZ*BDD1YO?40@ RZZ("$$/\RA40B RZZ("$$/MRC40D RZZRTT"ZPE40F RZZRTT"XNG40H RZZ+RTT2^TI40J RZZ%rtt,[QK40L RZZrtt$ZPM40N RZZrtt$ZPO40P RZZ2BDD9\RQ40R RZZ$bdd+HMS40T RZZ("$$/HMU40V RZZ*BDD1GLW40X RZZ%rtt,DIY40Z RZZ&-LQ[40\ RZZ("$$/YO]40` RZZErttLdSa40d RZZ,bdd3DIe40f RZZ&TJg40, 4p BJJ./BJJ}BJJ~BJJBJJyBJJ|%! +6"r6   