o
    jEiT                     @   s   d dl Z d dlZd dlmZ d dlmZmZ d dlmZ e e	Z
edddZedZdd	 Zed
dddd ZdddZed
dddddZed
dddddZdddZdS )    N)retry)datetime	timedelta)timezonei     zAmerica/Torontoc                 C   s6   t | trt| dks|  std|   dS dS )N
   zInvalid ASIN format: FT)
isinstancestrlenisalnumloggererror)asin r   3/var/www/agentarbitrage/keepa_deals/stable_deals.pyvalidate_asin   s   r      i  )stop_max_attempt_number
wait_fixedc              
   C   sn  t d|  d td|  d i d| dddg ddgd	d
gdddgdddgdddgdddgddddddddddddd d!d"d!dd!ddddd#d$d%}tj|d&d!d'}t d(|  tj|}d)| d*| }d+d,i}t d-|  ztj	||d.d/}t d0|j
  |jd1krt d2|j d3|j
  td2|j d3|j
  g W S | }|	d4i 	d5g }	t d6t|	 d7d8d9 |	D   t d:t|	d4i    t d;d<d9 |	D   t d=d>d9 |	D   td6t|	 d? |	W S  ty6 }
 zt d@t|
  td@t|
  g W  Y d }
~
S d }
~
ww )ANzFetching deals page z for Percent Down 90...pagedomainId1excludeCategoriesincludeCategoriesiR 
priceTypes   
deltaRangei  i&  deltaPercentRange2   isalesRankRangeiP  i` currentRangei  iu  	minRatingr   isLowestF
isLowest90isLowestOfferisOutOfStocktitleSearch isRangeEnabledTisFilterEnabled   3)filterEroticsingleVariation
hasReviewsisPrimeExclusivemustHaveAmazonOffermustNotHaveAmazonOffersortType	dateRange),:)
separators	sort_keyszRaw query JSON: zhttps://api.keepa.com/deal?key=z&selection=z
User-Agentz>Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/90.0.4430.212z
Deal URL:    )headerstimeoutzFull deal response:    zDeal fetch failed: z, dealsdrzFetched z deals: c                 S   s   g | ]}| d dqS )r   -)get.0dr   r   r   
<listcomp>G       z)fetch_deals_for_deals.<locals>.<listcomp>zDeal response structure: zAll deal keys: c                 S   s   g | ]}t | qS r   )listkeysr@   r   r   r   rC   I   rD   zDeals data: c              
   S   s~   g | ];}| d d| dg t| dg dkr#| ddgd d ndt| dg dkr9| ddgd d nddqS )r   r>   current	      r   )r   rG   z
current[9]z
current[1])r?   r
   r@   r   r   r   rC   J   s   ~ z dealszDeal fetch exception: )r   debugprintjsondumpsurllibparsequoterequestsr?   textstatus_coder   r
   rE   rF   	Exceptionr	   )r   api_key
deal_query
query_jsonencoded_selectionurlr9   responsedatar<   er   r   r   fetch_deals_for_deals   s   	

$ r^   c           	   	   C   s\  |r|nt }| dd}| dd}|d|  |dkr!d }ntt|d }|rtd|}|t}d	}|d
| d| dtj	  |d
| d| d|
   |d
| d| d|
   |d
| d| dt  |d
| d| d|
   |d
| d| d|j	  |d
| d| d|   d|
 iS ddiS )Nr   Unknown ASINcreationDater   zDeal found - raw ts=順 minutesUTC
deal_foundASIN:  - Timezone Debug (z) - KEEPA_EPOCH.tzinfo: z) - dt (naive UTC from Keepa): z) - utc_dt (aware UTC): z) - TORONTO_TZ object: z') - toronto_dt (converted to Toronto): z) - toronto_dt.tzinfo: z) - toronto_dt.utcoffset(): z
Deal foundr>   )r   r?   rK   KEEPA_EPOCHr   r   localize
astimezone
TORONTO_TZtzinfo	isoformat	utcoffset)	deal_objectlogger_paramcurrent_loggerr   tsdtutc_dt
toronto_dt	func_namer   r   r   re   S   s(   
    re   c              
   C   s  |r|nt }| d|r|ddnd}g }g }|r}t|tr}|dr}t|d tr}t|d dkr}t|d d tr}d|d d v r}|d d d }t|ttfrq|dkrq|| |d| d |	d	| d
|  n|	d	| d| d | d}t|ttfr|dkr|| |d| d |	d	| d|  n|	d	| d| d |rt|tr|dr|d d}	t|	ttfr|	dkr||	 |d|	 d |	d	| d|	  n|	d	| d|	 d |s|
d	| d|r|nd d ddiS t|}
|d	| d|
 d| d|  |
}|dkr;|
d	| d| d ddiS z|tt|d }td |}|t}|	d	| d!tj  |	d	| d"|   |	d	| d#|   |	d	| d$t  |	d	| d%|   |	d	| d&|j  |	d	| d'|   |d(}|	d)|  d|iW S  ty } z|
d*t|  ddiW  Y d }~S d }~ww )+Nr   r_   productsr   
lastUpdatera   z%product_data.products[0].lastUpdate ()rf   z - Found ts_product_general: z - ts_product_general (z) is invalid or None.zdeal_object.lastUpdate (z - Found ts_deal_general: z - ts_deal_general (statslastOffersUpdatez%product_data.stats.lastOffersUpdate (z - Found ts_offers_update: z - ts_offers_update (z-) from product_data.stats is invalid or None.zO - No valid timestamps found for last_update from any source. Sources checked: None.zlast updater>   z# - last_update: Selected latest_ts=z from candidates z. Sources considered: z? - No valid lastUpdate after considering all sources (final ts=rb   rd   z( - Timezone Debug - KEEPA_EPOCH.tzinfo: z/ - Timezone Debug - dt (naive UTC from Keepa): z( - Timezone Debug - utc_dt (aware UTC): z' - Timezone Debug - TORONTO_TZ object: z7 - Timezone Debug - toronto_dt (converted to Toronto): z' - Timezone Debug - toronto_dt.tzinfo: z, - Timezone Debug - toronto_dt.utcoffset(): %Y-%m-%d %H:%M:%Szlast update result: zlast_update failed: )r   r?   r   dictrE   r
   intfloatappendrK   r   maxinforh   r   r   ri   rj   rk   rl   rm   rn   strftimerU   r	   )ro   rp   product_datarq   r   possible_timestampssources_checkedts_product_generalts_deal_generalts_offers_update	latest_tsrr   rs   rt   ru   	formattedr]   r   r   r   last_updateq   st   "



""



r   c                 C   s,  |r|nt }| d|r|ddnd}d}d}|rt|tr|drt|d trt|d dkrt|d d trd|d d v rt|d d d tr|d d d }g d}g }	|d	| d
|  |D ]F}
|
t|k rt||
 tr||
 r||
 d }t|trt|dkr|d }t|ttfr|dkr|		| |d	| d|
 d|  qj|	rt
|	}dt|	 d| d}|d	| d| d|	  |dkr|d	| d| d | dg }g d}g }|d	| d|  |rt|tr|D ]A}|t|k r2|| }t|ttfr0|dkr0|	| |d	| d| d|  q|d	| d| dt| d q| dg }d}d}t||kr|| dkr|d	| d | d!| d" t||kr|| }t|ttfr|dkr|	| |d	| d#| d$|  n=|d	| d%| d&|  n.|d	| d't| d(| d) nt||kr|| nd*}|d	| d+| d,| d- |rt
|}d.t| d/}|d	| d0| d1|  n|d	| d2|  |d	| d3| d4|  |dkr#d	| d5| d}|| d6d7iS zKtt|d8 }td9|}|t}d:}|d	| d;| d<|  d=|  d>|  
 |d?}|d	| d@| dA| dB| d	 d6|iW S  ty } z|d	| dC| dt|  d6d7iW  Y d }~S d }~ww )DNr   r_   rI   zNo valid timestamp foundrw   r   csv)r               rf   zE - Checking product_data.csv for used item timestamps using indices: ra   z3 - Found product_data.csv timestamp for used index z: zproduct_data.csv (max of z# used item timestamps from indices ry   zE - Using product_data.csv for last used price change. Max timestamp: z. All found: zA - No valid used item timestamp from product_data.csv (latest_ts=z;). Falling back to deal_object.currentSince for used items.currentSince)r      rJ      r   zR - Checking deal_object.currentSince for used item timestamps using base indices: z; - Found deal_object.currentSince timestamp for used index z" - deal_object.currentSince index z out of bounds (len: z).rG          r   z( - Buy Box is Used (deal_object.current[z]==1). Checking currentSince[z] for Used Buy Box timestamp.zD - Found deal_object.currentSince timestamp for Used Buy Box (index z): z( - Used Buy Box timestamp (currentSince[z]) is invalid or not recent: z& - currentSince array too short (len: z) to check index z for Used Buy Box.zN/Az, - Buy Box is not Used (deal_object.current[z]=zD) or current array too short. Skipping Used Buy Box timestamp check.z!deal_object.currentSince (max of z7 used item timestamps including potential Used Buy Box)zM - Using deal_object.currentSince for last used price change. Max timestamp: z. All considered: z - No valid used item timestamps in deal_object.currentSince from specified indices (incl. Used Buy Box if applicable). Array was: z, - last used price change - selected raw ts=z from zO - No valid last *used* price change timestamp found from any source (final ts=zlast price changer>   rb   rd   last_price_changerg   z) - dt (naive UTC): z, utc_dt (aware UTC): z, toronto_dt: r~   z/ - last price change (focused on used) result: z
 (from ts z via zL - last_price_change (focused on used) failed during date conversion for ts )r   r?   r   r   rE   r
   rK   r   r   r   r   r   warningr   rh   r   r   ri   rj   rk   rm   r   rU   r	   )ro   rp   r   rq   r   r   source_descriptionproduct_csv_datarelevant_used_csv_indicestimestamps_from_csvindex
last_entryts_valcurrent_since_arrayrelevant_current_since_indicesvalid_current_since_tsicurrent_stats_arraybuy_box_is_used_indexbuy_box_used_price_ts_indexts_val_buy_box_usedbuy_box_is_used_vallog_messagers   rt   ru   rv   r   r]   r   r   r   r      s   "&"


&
$


4
$
 r   c                 C   s  |r|nt }| dd}| rt| dtr| d s'|d| d ddiS | d }dd	d
dddddddd
}td}d }|D ]T}|dg }	t|	dk rOq@z#t|	d }
t|	d }|dkrbd}|
| }||k rq|}|d}W q@ tt	fy } z|
d| d| d|	  W Y d }~q@d }~ww |d ur||v r|| }|d| d|d dd| d | d!	 d"|v r|d"d#}d|iS d$|v r|d$d%}d|iS |d| d&| d' dd(| d!iS |d| d) ddiS )*Nr   r_   offersrf   zA - Product data has no 'offers' list. Cannot determine condition.	Conditionr>   NewzUsed, like newzUsed, very goodz
Used, goodzUsed, acceptableRefurbishedzCollectible, like newzCollectible, very goodzCollectible, goodzCollectible, acceptable)
r   r   r   r*      r   r   r   rH   r   infofferCSVr   rI   r   	conditionz= - Could not parse price from offerCSV for one offer. Error: z. OfferCSV: z! - Found lowest priced offer at $d   z.2fz with condition: z (ry   zUsed, r'   zCollectible, zC-z1 - Found lowest priced offer but condition code 'z' is unknown.z	Unknown (z0 - No valid offers found to determine condition.)r   r?   r   rE   r   r   r
   r   
ValueError
IndexErrorrK   r   replace)r   rp   rq   r   r   condition_mappinglowest_pricebest_condition_codeofferoffer_historypriceshippingtotal_pricer]   condition_strr   r   r   get_condition4  sV   


*r   )N)NN)loggingrM   retryingr   r   r   pytzr   	getLogger__name__r   rh   rk   r   r^   re   r   r   r   r   r   r   r   <module>   s"   



9

Jw