
    =j                       d Z ddlmZ ddlZddlmZmZ ddlmZ ddlm	Z	m
Z
mZ ddlmZ dZ ej                  d	      Zd
ddddddddddddZ ej                  dej$                        Z ej                  dej$                        Z ej                  dej$                        Z ej                  dej$                        Zd"dZd#dZh dZ ej                  d      Z ej                  d      Zd$d Zd%d!Zy)&u  
Kohl's Rewards Visa (Capital One) statement parser — Story 9.8.

Tested against: Kohl's Visa ending 0532, period Apr 26 – May 26, 2026.

Format (Transactions section, page 2+):
  SAYRE GREENE #XXXX: Transactions
  Trans Date  Post Date  Description  Amount
  Apr 29  Apr 30  TST*CHUNKYS - MANCHESTEManchesterNH  $80.09

  - Dates: abbreviated month + day (e.g. "Apr 29"), year from statement header
  - Amount: "$XXX.XX" (positive for purchases)
  - Section headers: "SAYRE GREENE #XXXX: Transactions"
                     "SAYRE GREENE #XXXX: Payments, Credits and Adjustments"
  - Skip: "Trans Date", "Total Transactions", "Fees", "Interest Charged"

Year is extracted from: "Apr 26, 2026 - May 26, 2026 | N days in Billing Cycle"
    )annotationsN)datedatetime)Decimal)StagedTransaction
ParseErrorcompute_dedup_hash)	normalizez1.0.0z`^([A-Za-z]{3}\s+\d{1,2})\s+([A-Za-z]{3}\s+\d{1,2})\s+(.+?)\s+\$(-?\d{1,3}(?:,\d{3})*\.\d{2})\s*$                        	   
         )janfebmaraprmayjunjulaugsepoctnovdecz:\s*Transactions\s*$z:\s*Payments,?\s*Creditszr^(Total (Transactions|Fees)|Fees$|Interest Charged|Totals Year|Interest Charge Calculation|Additional Information)uw   ^(Trans Date|Visit Kohls|Page \d+|Kohl.s Rewards|Apr \d+, 20\d\d|Payment Information|Account Summary|SAYRE |© 20|ETC-)c                   	 ddl }g }g }	 |j	                  |       5 }g }t        |j                  d      D ]N  \  }}|j                         xs dj                  d      D ]#  }|j                  ||j                         f       % P 	 ddd       t              }	d}
|D ]Y  \  }}|s
t        j                  |      rd	}
"t        j                  |      rd
}
:t        j!                  |      r|
dk7  rd}
W|
dvr\t"        j!                  |      rrt$        j!                  |      }|s|j'                  d      }|j'                  d      j                         }|j'                  d      }	 t)        ||	      }	 t/        |j1                  dd            }|t/        d      k  xs |
d
k(  }t5        |      }t7        |      }t9        |      }t;        |||      }|j                  t=        |||||d|d|	             \ 	 ||fS # t        $ r g t        dddt              gfcY S w xY w# 1 sw Y   xY w# t*        $ r5}|j                  t        ||t-        |      t                     Y d}~d}~ww xY w# t2        $ r5}|j                  t        ||t-        |      t                     Y d}~d}~ww xY w# t2        $ r7}|j                  t        dt-        |      dt                     Y d}~||fS d}~ww xY w)z8Parse a Kohl's Rewards Visa (Capital One) statement PDF.r   N zpdfplumber not installedr   )start
nonetransactionspaymentsdone)r(   r)   r   r   ,0kohlsg?)	r   merchant_rawmerchant_normalizedamount	is_creditissuer
dedup_hashconfidence_scoreraw_textzFailed to open or read PDF)
pdfplumberImportErrorr   _PARSER_VERSIONopen	enumeratepagesextract_textsplitappendstrip_extract_year_SECTION_TRANSACTIONSsearch_SECTION_PAYMENTS_ENDS_SECTIONmatch_SKIP_RE_TXN_REgroup_parse_month_day
ValueErrorstrr   replace	Exceptionabs_strip_locationr
   r	   r   )pdf_pathr6   r(   errorspdf	all_linespage_numpagelinestatement_yearstatemtrans_date_strdescription
amount_strtxn_dateexcr0   r1   
abs_amount
clean_descnormr3   s                          :/var/www/html/financials/app/services/pdf_parsers/kohls.pyparserc   7   s   T -/L!FI^__X& 	?#/1I"+CIIQ"? ?$!..06B==dC ?D$$h

%=>??	? 'y1 ' :	NHd$++D1& ''-"""4(F?"E88~~d#d#AWWQZNWWQZ--/KWWQZJ+NNK
 !3!3C!<=
 -D*1DIVJ )5JZ(D+D*hGJ 1($(!#%!%
! 
a:	~ c  TJq"&@/RSSST	? 	?R  j4S?ST  j4S?ST0  ^jCH.JO\]]^s   H J4 A+H%C"J4 +H28I3A)J4 H"!H"%H/*J4 2	I0;*I+%J4 +I00J4 3	J1<*J,&J4 ,J11J4 4	K4=*K//K4c                    | j                         j                         }t        j                  |d   j	                               }|st        d|d          t        |d         }t        |||      S )u%   Parse "Apr 29" → date(year, 4, 29).r   zUnknown month abbreviation: r   )r?   r=   _MONTH_ABBRgetlowerrJ   intr   )textyearpartsmonthdays        rb   rI   rI      se    JJL EOOE!HNN,-E7azBCC
eAh-CeS!!    >3   AKALARAZCACOCTDCDEFLGAHIIAIDILINKSKYLAMAMDMEMIMNMOMSMTNCNDNENHNJNMNVNYOHOKORPARISCSDTNTXUTVAVTWAWIWVWYz%^(.+?)\s+-\s+[A-Za-z].{0,20}[A-Z]{2}$z^(.*?)\s*\S+([A-Z]{2})$c                   t         j                  |       }|rI|j                  d      dd j                         }|t        v r|j                  d      j                         S t        |       dk\  rP| dd j                         t        v r7t        j                  dd|       j                         }|rt        |      dk\  r|S | S )	u  
    Strip Capital One city+state PDF rendering artifacts.
    e.g. "TST*CHUNKYS - MANCHESTEManchesterNH" → "TST*CHUNKYS"
         "WALGREENS #10378EAST HAMPSTEANH"      → "WALGREENS #10378"
         "KOHLS 0538SALEMNH"                    → "KOHLS 0538"
    r   Nr   r   z[A-Za-z]+[A-Z]{2}$r$   r   )	_LOCATION_DASH_RErE   rH   upper
_US_STATESr?   lenresub)ri   rY   last_twostrippeds       rb   rO   rO      s     	%A771:bc?((*z!771:##%% 4yA~$rs)//+z966/T:@@BH*OKrn   c                    | D ]9  \  }}t        j                  d|      }|st        |j                  d            c S  t	        j
                         j                  S )zJExtract year from 'Apr 26, 2026 - May 26, 2026 | N days in Billing Cycle'.z\b(20\d{2})\br   )r   rB   rh   rH   r   nowrj   )lines_rV   rY   s       rb   r@   r@      sO     #4II&-qwwqz?"# <<>rn   )rP   rK   returnz0tuple[list[StagedTransaction], list[ParseError]])ri   rK   rj   rh   r   r   )ri   rK   r   rK   )r   zlist[tuple[int, str]]r   rh   )__doc__
__future__r   r   r   r   decimalr   app.services.pdf_parsers.baser   r   r	    app.services.merchant_normalizerr
   r8   compilerG   re   IrA   rC   rD   rF   rc   rI   r   r   _LOCATION_CONCAT_RErO   r@    rn   rb   <module>r      s  $ # 	 #  [ [ 6 "**g
 Qq1QQqBr
 $$;RTTB #$?F #;DD
 2::>DDU p"
 BJJGH  bjj!;< 2rn   