
    mjp<                    B   d dl mZ d dlZd dlmc mZ d dlZd dl	m
Z
 d dlZd dlmZmZ d dlmZmZmZmZmZmZmZmZmZmZmZmZ d dlmZmZmZm Z m!Z! d!d	Z"d"d#dZ# G d de           Z$d$dZ%d$dZ&d$dZ'd$dZ(d$dZ)d%dZ*d$dZ+d$dZ,d$dZ-d$dZ.d$dZ/d$dZ0d$d Z1dS )&    )annotationsN)Path)apply_migrationsget_schema_version)add_demo_migros_receiptaccept_grocery_product_matchreject_grocery_product_matchcreate_manual_grocery_mappingrefresh_grocery_mapping_priceget_grocery_optimizer_dashboardrun_grocery_optimization$generate_grocery_optimization_reportget_grocery_provider_strategybuild_rappn_link_outpreview_manual_grocery_mappingconfirm_manual_grocery_mapping) search_and_store_product_matchessearch_open_prices_spikeCoopProviderGroceryProductProviderGroceryProviderResultreturnsqlite3.Connectionc                    t          j        d          } t           j        | _        t	          |            t          |           }d}||k    }|st          j        d|fd||f          dt          j	                    v st          j
        t
                    rt          j        t
                    nddt          j	                    v st          j
        |           rt          j        |           ndt          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x}x}}| S )
Nz:memory:1   ==)z0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} == %(py6)sr   conn)py0py1py3py6zassert %(py8)spy8)sqlite3connectRowrow_factoryr   r   
@pytest_ar_call_reprcompare@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)r   @py_assert2@py_assert5@py_assert4@py_format7@py_format9s         X/home/agent/.hermes/repos/FinanceManager/tests/unit/test_grocery_matching_learning_v2.pydbr6      sP   ?:&&D{DTd##)r)#r))))))))))#r))))))))))))))))))))))))))))))d)))))d))))))#))))r)))))))))))))))))))))))))))K    Milch 1Lr1r   dictc                8    t          | dd||dddddg          S )	N
2026-05-19Migros1Llz1.50/lz1.50)raw_product_namequantity_textunitunit_price_texttotal_price_text)purchase_date
store_name
receipt_iditems)r   )r   rawrG   s      r5   seed_receiptrJ   "   s_    "4|PXeo  NQ  dh  ru  JR  hn  yo  yo  xp  q  q  q  qr7   c                  *     e Zd Zd fdZdddZ xZS )StaticProviderretailerstrresultslist[GroceryProviderResult]r   Nonec                    t                                          d            || _        d|                                                    dd           d| _        || _        d S )Nc                    dS )N  _urls    r5   <lambda>z)StaticProvider.__init__.<locals>.<lambda>(   s    b r7   fetcherzhttps:// -z	.example/)super__init__rM   lowerreplacebase_url_results)selfrM   rO   	__class__s      r5   r^   zStaticProvider.__init__'   s^    111 P8>>#3#3#;#;C#E#EPPPr7   Nde-CHT   Q r   r   query
str | Nonelocale	use_cacheboolmax_resultsintmax_age_seconds
list[dict]c                T    | xj         dz  c_         d | j        d |         D             S )N   c                6    g | ]}|                                 S rU   )as_dict).0rs     r5   
<listcomp>z2StaticProvider.search_products.<locals>.<listcomp>/   s     AAA		AAAr7   )request_countrb   )rc   r   rh   rM   rj   rk   rm   ro   s           r5   search_productszStaticProvider.search_products-   s5    aAAT]<K<%@AAAAr7   )rM   rN   rO   rP   r   rQ   )Nre   Trf   rg   )r   r   rh   rN   rM   ri   rj   rN   rk   rl   rm   rn   ro   rn   r   rp   )__name__
__module____qualname__r^   ry   __classcell__)rd   s   @r5   rL   rL   &   s_                   B B B B B B B B Br7   rL   rQ   c                 6   t                      } t          | d          }t          d           }t          | d|g|d         d         d         gd	          }t	          | |d
         d         d         d          }|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}t          | d          }
t          d           }t          | d|g|
d         d         d         gdd          }|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}|d
         d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}t          | ddg|
d         d         d         g           }|d!         d"         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}d S )#Nr9   rG   c                    dS )Nz<article data-product><a href="/milch">Prix Garantie Milch 1L</a><span class="price">CHF 1.20</span><span class="unit-price">1.20/l</span></article>rU   rV   s    r5   rX   zktest_accept_match_creates_preferred_mapping_and_next_receipt_reuses_without_provider_call.<locals>.<lambda>5   s
      2H r7   rY   rH   r   product_item_idF	providersincluded_product_item_idsrk   matchesmatch_idpasst	user_notestatusacceptedr   z%(py1)s == %(py4)sr    py4assert %(py6)sr"   target_retailerCoopr2c                Z    d dD                                  t          d                    S )Nc              3     K   | ]}|V  d S )NrU   )ru   _s     r5   	<genexpr>z~test_accept_match_creates_preferred_mapping_and_next_receipt_reuses_without_provider_call.<locals>.<lambda>.<locals>.<genexpr><   s      ooQqoooooor7   rU   zprovider must not be called)throwr.   rV   s    r5   rX   zktest_accept_match_creates_preferred_mapping_and_next_receipt_reuses_without_provider_call.<locals>.<lambda><   s'    oo"ooo6K6KN[xLyLy6z6z r7   Tr   r   prefer_known_mappingsrk   provider_callsknown_mapping_hitsrr   sourceknown_mappingselected_retailersr   summaryreplaceable_product_count)r6   rJ   r   r   r   r(   r)   r-   r.   r/   r   )r   firstproviderfoundr   @py_assert0@py_assert3r0   @py_format5r3   secondfail_providerreusedruns                 r5   Ytest_accept_match_creates_preferred_mapping_and_next_receipt_reuses_without_provider_callr   2   s~   44D$///E  %H  %H  I  I  IH,T4H:jopwjxyzj{  }N  kO  jP  \a  b  b  bE+D%	2B12Ej2Q]deeeHH++++++++++++++++++++++++++++++++++++++++++++++++%&0&0&&0000000000&&00000&0000&000000000000000000000000000$4000F )z)z{{{M-dD]Opvw~p  AB  qC  DU  qV  pW  os  C  D  D  DF"#(q(#q((((((((((#q(((((#((((q(((((((((((((((((((((((((((&',1,'1,,,,,,,,,,'1,,,,,',,,,1,,,,,,,,,,,,,,,,,,,,,,,,,,,)Q)<_<)_<<<<<<<<<<)_<<<<<)<<<<_<<<<<<<<<<<<<<<<<<<<<<<<<<<
"46(gmnugvwxgy  {L  hM  gN  O  O  OCy>56;!;6!;;;;;;;;;;6!;;;;;6;;;;!;;;;;;;;;;;;;;;;;;;;;;;;;;;;;r7   c                 l   t                      } t          |           }t          d           }t          | d|g|d         d         d         gd          }t	          | |d	         d         d
         d          }|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}t          | d          }
t          | d|g|
d         d         d         gdd          }d |d	         D             }t          |          }|sddt          j                    v st          j        t                    rt          j        t                    ndt          j        |          t          j        |          dz  }t          t          j	        |                    d x}}t          | ddg|
d         d         d         g          }|d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}d }|d!         d         d"         }||v }|slt          j        d#|fd$||f          t          j        |          t          j        |          dz  }dd|iz  }	t          t          j	        |	                    d x}x}}d S )%Nc                    dS )Nz<article data-product><a href="/milch">Coop Milch 1L</a><span class="price">CHF 1.20</span><span class="unit-price">1.20/l</span></article>rU   rV   s    r5   rX   zLtest_rejected_match_is_persisted_and_not_recommended_again.<locals>.<lambda>H   s
      2 r7   rY   r9   rH   r   r   Fr   r   r   falschr   r   rejectedr   r   r   r   r"   r   r   Tr   c              3  H   K   | ]}|                     d           dk    V  dS )r   	suggestedN)getru   ms     r5   r   zMtest_rejected_match_is_persisted_and_not_recommended_again.<locals>.<genexpr>O   s1      II!quuX+-IIIIIIr7   ,assert %(py4)s
{%(py4)s = %(py0)s(%(py2)s)
}allr   py2r   r   r   r   r   r8   optimized_listsrejected_productsinz%(py1)s in %(py4)s)r6   rJ   r   r   r	   r(   r)   r-   r.   r/   r   r*   r+   r,   r   )r   receiptr   r   r   r   r   r0   r   r3   r   r   @py_assert1r   s                 r5   :test_rejected_match_is_persisted_and_not_recommended_againr   E   s   44D4  G  %  %  @  @  @H,T4H:jqryjz{|j}  P  kQ  jR  ^c  d  d  dE+D%	2B12Ej2Q]efffHH++++++++++++++++++++++++++++++++++++++++++++++++$4000F-dDXJkqrykz{|k}  P  lQ  kR  jn  z~      FIIvi7HIIII3IIIIIIIIIIIIIIII3IIIII3IIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
"46(gmnugvwxgy  {L  hM  gN  O  O  OCy>56;!;6!;;;;;;;;;;6!;;;;;6;;;;!;;;;;;;;;;;;;;;;;;;;;;;;;;;G./23FGG:GGGGGGGGGGG:GGGGGG:GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGr7   c                    t                      } t          |           }t          | |d         d         d         ddddddd	d
dd          }|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         }d	}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          | ddg|d         d         d         g          }|d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}| 	                    d           t          | |d                   }	|	d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          | ddg|d         d         d         g          }
|
d          }d
}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d S )!NrH   r   r   DennerDenner Milch 1Lhttps://www.denner.ch/milchr>   r?   manual_match1.101.10/lzmanuell notiert)r   r   target_product_nametarget_product_urltarget_brandtarget_package_sizetarget_unit
match_typecandidate_price_textcandidate_unit_price_textr   r   r   r   r   r   r   r"   r   last_price_checked_atisz%(py1)s is %(py4)sr9   r   r   r   aT  INSERT INTO grocery_product_details_cache(detail_id,retailer,product_url,product_name,price_text,unit_price_text,package_size,ingredients_text,nutrition_json,fetched_at,cache_status,source_hash) VALUES ('d1','Denner','https://www.denner.ch/milch','Denner Milch 1L','1.10','1.10/l','1L',NULL,'{}','2026-05-19T10:00:00+00:00','cached','hash')
mapping_idz2026-05-19T10:00:00+00:00optimized_total_text)r6   rJ   r
   r(   r)   r-   r.   r/   r   executer   )r   r   mappingr   r   r0   r   r3   
run_before	refreshed	run_afters              r5   Etest_manual_mapping_can_be_saved_and_used_after_sourced_cache_refreshr   U   s`   44D4  G+D''BRSTBUVgBh  {C  Yj  \  ks  IM  [^  ky  PV  rz  FW  X  X  XG8*
*
**********
*********
***************************< 2N2 N2222222222 N22222 2222N222222222222222222222222222*+3t3+t3333333333+t33333+3333t333333333333333333333333333)$(pwx  qA  BC  qD  EV  qW  pX  Y  Y  YJi !<=BB=BBBBBBBBBB=BBBBB=BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBLL  h  i  i  i-dGL4IJJI,-L1LL-1LLLLLLLLLLL-1LLLLLL-LLLL1LLLLLLLLLLLLLLLLLLLLLLLLLLLL(t
ovw~o  AB  pC  DU  pV  oW  X  X  XI+,66,6666666666,66666,666666666666666666666666666666666r7   c            	        t                      } t          |           }dD ]Y}t          j        t                    5  t          | |d         d         d         dd|           d d d            n# 1 swxY w Y   Zt          j        t                    5  t          | |d         d         d         dddd	
           d d d            d S # 1 swxY w Y   d S )N)zjavascript:alert(1)zhttp://127.1/xzhttp://[::1]/xzhttp://169.254.169.254/latestzhttp://172.31.0.1/xzhttp://localhost/xrH   r   r   r   Bad)r   r   r   r   zhttps://coop.example/bad
evil_match)r   r   r   r   r   )r6   rJ   pytestraises
ValueErrorr
   )r   r   
unsafe_urls      r5   5test_manual_mapping_rejects_unsafe_url_and_match_typer   e   s   44D4  G ` z z
]:&& 	z 	z)$@PQR@STe@fx~  UZ  oy  z  z  z  z	z 	z 	z 	z 	z 	z 	z 	z 	z 	z 	z 	z 	z 	z 	z	z	"	" _ _%dGG<LQ<OPa<btz  QV  kE  R^  	_  	_  	_  	__ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _s#   'A..A2	5A2	(CCCc            	     .   t                      } t          |           }t          | |d         d         d         ddddd	          }t          |           }|d
         d         d         d         }|d         d         d         }|d         }||k    }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }	t          t	          j        |	                    d x}x}}|d         d         d         }h d}||v }|slt	          j        d|fd||f          t	          j        |          t	          j        |          dz  }dd|iz  }	t          t	          j        |	                    d x}x}}d S )NrH   r   r   r   Coop Milch 1Lhttps://coop.example/milchr   1.20r   r   r   r   r   r   receiptsknown_mappingsr   r   r   r   r   r"   cache_status>   fehltfehlerfrischveraltetr   r   )	r6   rJ   r
   r   r(   r)   r-   r.   r/   )
r   r   r   dashitemr   r   r0   r   r3   s
             r5   7test_dashboard_surfaces_known_mappings_and_cache_statusr   o   s   44D4  G+D''BRSTBUVgBh  {A  Wf  {W  dr  IO  P  P  PG*400D
Aw'*D !!$\2Kgl6KK26KKKKKKKKKKK26KKKKKK2KKKK6KKKKKKKKKKKKKKKKKKKKKKKKKKKK !!$^4a8a8a8aa48aaaaaaaaaaa48aaaaaa4aaaa8aaaaaaaaaaaaaaaaaaaaaaaaaaaaaar7   tmp_pathr   c           	     *   t                      }t          |          }t          ||d         d         d         ddddd	           t          |d
dg|d         d         d         g          }t	          ||d         | dz  | dz            }t          |d                                                   }|d         }d}||u }|slt          j        d|fd||f          t          j	        |          t          j	        |          dz  }	dd|	iz  }
t          t          j        |
                    d x}x}}d}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d }||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d!}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d"}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d#}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d$}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d%}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d&}||v }|st          j        d|fd||f          t          j	        |          dt          j                    v st          j        |          rt          j	        |          nddz  }dd|iz  }t          t          j        |                    d x}}d S )'NrH   r   r   r   r   r   r   r   r   r9   r   run_idzruntime-reportsrepo)reports_dir	repo_rootreport_pathruntime_onlyTr   r   r   r   r"   zBon-Auswahlr   )z%(py1)s in %(py3)stext)r    r!   zassert %(py5)spy5zAnalysierte ProduktezAkzeptierte AlternativenzAbgelehnte AlternativenzUnsichere ProduktezNicht gefundene Produkteu.   Geschätzte Ersparnis nur aus sicheren MatcheszBekannte Mappingszkeine medizinische Empfehlung)r6   rJ   r
   r   r   r   	read_textr(   r)   r-   r.   r/   r*   r+   r,   )r   r   r   r   reportr   r   r   r0   r   r3   @py_format4@py_format6s                r5   Gtest_report_contains_known_mappings_sources_and_disclaimer_runtime_onlyr  y   sb	   44D4  G!$8H8KL]8^pv  M\  qM  Zh  E  F  F  F  F
"46(gnovgwxygz  |M  hN  gO  P  P  PC1$HS[^oSo  |D  GM  |M  N  N  NF}%&&0022D.!)T)!T))))))))))!T)))))!))))T))))))))))))))))))))))))))) =D          =D     =           D     D                           !)!T))))))))))!T)))))!)))))))))))T)))))T)))))))))))))))))))))))))))%-%----------%-----%-------------------------------------------$,$,,,,,,,,,,$,,,,,$,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,'4''''''''''4''''''''''''''''4'''''4'''''''''''''''''''''''''''%-%----------%-----%-------------------------------------------;C;tCCCCCCCCCC;tCCCCC;CCCCCCCCCCCtCCCCCtCCCCCCCCCCCCCCCCCCCCCCCCCCC&$&&&&&&&&&&$&&&&&&&&&&&&&&&&$&&&&&$&&&&&&&&&&&&&&&&&&&&&&&&&&&'/'4//////////'4/////'///////////4/////4///////////////////////////*2*d2222222222*d22222*22222222222d22222d22222222222222222222222222222r7   c                 @   t                      } t          |           }t          dt          dddd d d          g          }t	          | d|g|d         d         d	         gd
          }|d         d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|d         d         d         }|s:ddt          j        |          iz  }	t          t          j	        |	                    d }t          | |d         d         d         d
          }
|
d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}|
d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}t          | |d         d         d                   }|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j	        |                    d x}x}}d S )Nr   zCoop Milch ohne Preiszhttps://coop.example/no-pricez0.50)rM   product_nameproduct_url
price_textrC   
confidencer9   rH   r   r   Fr   r   r   needs_reviewr   r   r   r   r"   r   assert %(py1)sr    )save_as_preferredr   r   r   )r6   rJ   rL   r   r   r(   r)   r-   r.   r/   r   r	   )r   r   r   r   r   r   r0   r   r3   @py_format2r   r   s               r5   <test_no_price_provider_candidate_is_persisted_and_rejectabler     s   44D4  Gf'<f[r  A`  mq  CG  TZ  ([  ([  ([  '\  ]  ]H,T4H:jqryjz{|j}  P  kQ  jR  ^c  d  d  dEAx(:N:(N::::::::::(N:::::(::::N:::::::::::::::::::::::::::Az*************************+D%	2B12Ej2QejkkkHH////////////////////////////////////////////////L!3^3!^3333333333!^33333!3333^333333333333333333333333333+D%	2B12Ej2QRRHH++++++++++++++++++++++++++++++++++++++++++++++++++r7   c                 X   t                      } t          |           }t          dt          ddddddgd          g          }t	          | d	|g|d
         d         d         gd          }t          | |d         d         d                    t          dt          ddddddgd          g          }t          | d          }t	          | d|g|d
         d         d         gdd          }d |d         D             }t          |          }|sddt          j                    v st          j
        t                    rt          j        t                    ndt          j        |          t          j        |          dz  }	t          t          j        |	                    d x}}d S )Nr   r   r   r   z1.20/lclose_matchz0.80)rM   r  r  r  rC   quality_flagsr  r9   rH   r   r   Fr   r   r   r   r   zhttps://denner.example/milchr   r   r   r   Tr   c              3  F   K   | ]}|d          dk    o|d         dk    V  dS )rM   r   r   r   NrU   r   s     r5   r   zNtest_rejected_exact_match_does_not_suppress_other_retailers.<locals>.<genexpr>   s9      hhAq}(GQx[K-Ghhhhhhr7   r   anyr   )r6   rJ   rL   r   r   r	   r  r*   r+   r(   r,   r-   r.   r/   )
r   r   coopr   dennerr   found_againr   r   r   s
             r5   ;test_rejected_exact_match_does_not_suppress_other_retailersr     se   44D4  G&#8&Wf  uQ  ^d  v~  O\  N]  jp  $q  $q  $q  #r  s  sD,T4D6fmnufvwxfy  {L  gM  fN  Z_  `  `  `E uY'7'::'FGGGH'<h]n  }[  hn  @H  Yf  Xg  tz  ({  ({  ({  '|  }  }F$4000F24&ntu|n}~  oA  BS  oT  nU  mq  }B  C  C  CKhhQ\]fQghhhh3hhhhhhhhhhhhhhhh3hhhhh3hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhr7   c                 0   t                      } t          d | d         D                       }|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x}x}}g }d
}|d         }||v }	|	}|	sd
}
| d         d         }|
|v }|}|st          j        d|	fd||f          t          j        |          t          j        |          dz  }dd|iz  }|                    |           |	s`t          j        d|fd|
|f          t          j        |
          t          j        |          dz  }dd|iz  }|                    |           t          j        |d          i z  }dd|iz  }t          t          j        |                    d x}x}x}x}	x}x}
x}}| d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x}x}}d | d         d         D             }t          |          }|sd d!t          j                    v st          j        t                    rt          j        t                    nd!t          j        |          t          j        |          d"z  }t          t          j        |                    d x}}d# | d         d$         D             }t          |          }|sd d!t          j                    v st          j        t                    rt          j        t                    nd!t          j        |          t          j        |          d"z  }t          t          j        |                    d x}}t          d%          }|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x}x}}|d&         }d'}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x}x}}d(}|d)         }||v}|slt          j        d*|fd+||f          t          j        |          t          j        |          dz  }dd	|iz  }t          t          j        |                    d x}x}}d S ),Nc              3  2   K   | ]}|d          dk    |V  dS )r   zRappn.chNrU   ru   rows     r5   r   zPtest_provider_strategy_documents_rappn_linkout_and_llm_limits.<locals>.<genexpr>   s1      ]]s:R\?\?\?\?\?\?\]]r7   provider_matrixofficial_apiFr   r   r   r   r"   zLink-Outrecommendationrappnmoder   )z%(py3)s in %(py6)s)r!   r"   z%(py8)sr#   )z%(py11)s in %(py14)s)py11py14z%(py16)spy16rr   zassert %(py19)spy19link_out_onlyr   r   c              3     K   | ]}d |v V  	dS )zPreise erfindenNrU   ru   r   s     r5   r   zPtest_provider_strategy_documents_rappn_linkout_and_llm_limits.<locals>.<genexpr>   s(      YYT D(YYYYYYr7   
llm_policy	forbiddenr   r  r   c              3     K   | ]}d |v V  	dS )zProduktnamen normalisierenNrU   r%  s     r5   r   zPtest_provider_strategy_documents_rappn_linkout_and_llm_limits.<locals>.<genexpr>   s(      bb+t3bbbbbbr7   allowedr8   manual_sourcemanual/rappn_user_checkedz	api.rappnurl)not in)z%(py1)s not in %(py4)s)r   nextr(   r)   r-   r.   r/   append_format_boolopr  r*   r+   r,   r   )strategyr  r   r   r0   r   r3   r   r1   r2   @py_assert10@py_assert13@py_assert12r4   @py_format15@py_format17@py_format18@py_format20links                      r5   =test_provider_strategy_documents_rappn_linkout_and_llm_limitsr:     s   ,..H]]): ;]]]]]E )E) E)))))))))) E))))) ))))E)))))))))))))))))))))))))))[[:[/0[:00[[[[[J[(7BSTZB[[JB[4[[[[[[[[[[[[:0[[[[[:[[[[0[[[[[[[[[[[[[[[[[[[[[[[[[[[JB[[[[[[J[[[[B[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[GV$77$7777777777$77777$7777777777777777777777777777777YYXl5KK5XYYYY3YYYYYYYYYYYYYYYY3YYYYY3YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYbb@VW`@abbbb3bbbbbbbbbbbbbbbb3bbbbb3bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
++D<*?*<?**********<?*****<****?*************************** ?$?? $??????????? $?????? ????$????????????????????????????)d5k);k))))))))));k)))));))))k)))))))))))))))))))))))))))))r7   c                   
 ddddddddid	d
ddgi
t          d
fd          } | d         d         }|d         }|j        }d} ||          }|ssdt          j        |          t          j        |          t          j        |          t          j        |          dz  }t	          t          j        |                    d x}x}x}}|d         }d }||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t	          t          j        |	                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }	t	          t          j        |	                    d x}x}}d}|d         }||v }|slt          j        d|fd ||f          t          j        |          t          j        |          dz  }dd|iz  }	t	          t          j        |	                    d x}x}}d S )!NrH      123Milch1coder  product_quantityosm_namez	Test Shopr<   CHF)datecurrency)idproductlocationproofc                H    t          d                                        S Njson
__import__dumpsrW   payloads    r5   rX   z@test_open_prices_without_price_is_never_secure.<locals>.<lambda>       *U[J\J\JbJbcjJkJk r7   )rh   rZ   
candidatesr   
source_urlz/7Jassert %(py7)s
{%(py7)s = %(py3)s
{%(py3)s = %(py1)s.endswith
}(%(py5)s)
}r    r!   r   py7r  r   r   r   r   r"   can_count_as_secure_savingFno_pricer  r   r   )r   endswithr(   r-   r.   r/   r)   )result	candidater   r0   r2   @py_assert6@py_format8r   r   r3   rR  s             @r5   .test_open_prices_without_price_is_never_securer`     s:   ugkn.o.o  I  KV  ~W  kw  EJ  bK  bK  L  L  M  NG%G=k=k=k=klllF|$Q'I\"1"+1D1++D11111111"1111+1111D1111111111111111111111111111\"*d*"d**********"d*****"****d***************************12;e;2e;;;;;;;;;;2e;;;;;2;;;;e;;;;;;;;;;;;;;;;;;;;;;;;;;;3?33:33333333333:333333:3333333333333333333333333333333333r7   c            	     H   ddddddddd	d
diddidgit          dfd          } | d         d         }|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t	          t          j        |                    d x}x}}|d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t	          t          j        |                    d x}x}}|d         }|j        }d} ||          }|ssdt          j        |          t          j        |          t          j        |          t          j        |          dz  }	t	          t          j        |	                    d x}x}x}}|d         }d}||u }|slt          j        d |fd!||f          t          j        |          t          j        |          dz  }dd|iz  }t	          t          j        |                    d x}x}}|d"         }|s:d#d$t          j        |          iz  }
t	          t          j        |
                    d }d S )%NrH      z1.25rD  r<   r=  r>  r>   r@  rC  z	Open ShoprE  z
2026-05-18)rG  pricerF  rE  rH  rI  rJ  c                H    t          d                                        S rL  rN  rQ  s    r5   rX   zRtest_open_prices_with_price_still_candidate_with_source_and_date.<locals>.<lambda>   rS  r7   )barcoderZ   rT  r   r  r   r   r   r   r"   
price_daterU  z/8rV  rW  rY  Fr   r   attributionr	  r    )r   r(   r)   r-   r.   r/   r[  )r\  r]  r   r   r0   r   r3   r2   r^  r_  r  rR  s              @r5   @test_open_prices_with_price_still_candidate_with_source_and_daterh     s   F|qv  IP  fj  ik  ik  zD  FQ  yR  ^d  fr  ]s  t  t  u  vG%e=k=k=k=klllF|$Q'I\",f,"f,,,,,,,,,,"f,,,,,",,,,f,,,,,,,,,,,,,,,,,,,,,,,,,,,\"2l2"l2222222222"l22222"2222l222222222222222222222222222\"1"+1D1++D11111111"1111+1111D111111111111111111111111111112;e;2e;;;;;;;;;;2e;;;;;2;;;;e;;;;;;;;;;;;;;;;;;;;;;;;;;;]###########################r7   c                    t                      } t          |           }|d         d         d         }t          | |dddddd	d
ddd          }|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          | |          }	|	d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|	d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}| 	                    d|f          
                                }
d |
D             }ddg}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          | ddg|g           }|d!         d"         }d#}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|d!         d$         }d%}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d S )&NrH   r   r   r   r   r   r   r   r>   r?   r<   r+  u   manuell geprüft)r   r   r   r   r   r   r   r   target_price_datetarget_price_sourcer   requires_confirmTr   r   r   r   r"   rY  rj  r   r   rk  z[SELECT action FROM grocery_mapping_audit_events WHERE product_item_id=? ORDER BY created_atc                    g | ]
}|d          S )actionrU   r  s     r5   rw   z[test_manual_price_preview_confirm_audit_and_secure_saving_when_complete.<locals>.<listcomp>   s    ,,,cCM,,,r7   manual_mapping_previewmapping_insertedr9   r   r   r   rr   estimated_savings_textz0.40)r6   rJ   r   r(   r)   r-   r.   r/   r   r   fetchallr   )r   r   item_idpreviewr   r   r0   r   r3   r   auditsr   s               r5   Gtest_manual_price_preview_confirm_audit_and_secure_saving_when_completerv     s   44D4  Ggq!"34G,T7\d  {L  a~  U[  w  UY  gj  ~J  `{  GY  Z  Z  ZG%&.$.&$..........&$.....&....$.........................../08D80D88888888880D8888808888D888888888888888888888888888,T7;;G&'7<7'<7777777777'<77777'7777<777777777777777777777777777()H-HH)-HHHHHHHHHHH)-HHHHHH)HHHH-HHHHHHHHHHHHHHHHHHHHHHHHHHHH\\w  {B  zD  E  E  N  N  P  PF,,V,,,^1IK]0^^,0^^^^^^^^^^^,0^^^^^^,^^^^0^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"48*iphq
r
r
rCy>56;!;6!;;;;;;;;;;6!;;;;;6;;;;!;;;;;;;;;;;;;;;;;;;;;;;;;;;y>23=v=3v==========3v=====3====v=============================r7   c            	        t                      } t          |           }|d         d         d         }t          | |ddddd	          }|d
         }d}||u }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          | |          }	d}|	d         }||v }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}t          | ddg|g          }
|
d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}|
d         d         }d}||k    }|slt          j        d|fd||f          t          j        |          t          j        |          dz  }dd|iz  }t          t          j        |                    d x}x}}d S )NrH   r   r   r   r   r   r   r   )r   r   r   r   r   r   rY  Fr   r   r   r   r"   r  quality_flags_jsonr   r   r9   r   r   r   r   r   rq  z0.00)
r6   rJ   r   r(   r)   r-   r.   r/   r   r   )r   r   rs  rt  r   r   r0   r   r3   r   r   s              r5   Etest_manual_price_without_date_source_is_review_only_no_secure_savingry     sH   44D4  Ggq!"34G,T7\d  {L  a~  U[  w  @  @  @G/09E90E99999999990E9999909999E999999999999999999999999999,T7;;G:W%9::>:::::::::::>::::::>::::::::::::::::::::::::::::::::
"48*iphq
r
r
rCy>56;!;6!;;;;;;;;;;6!;;;;;6;;;;!;;;;;;;;;;;;;;;;;;;;;;;;;;;y>23=v=3v==========3v=====3====v=============================r7   )r   r   )r8   r9   )r   r   r   r:   )r   rQ   )r   r   r   rQ   )2
__future__r   builtinsr*   _pytest.assertion.rewrite	assertionrewriter(   r$   pathlibr   r   !jarvis_finance.storage.migrationsr   r   )jarvis_finance.services.grocery_optimizerr   r   r	   r
   r   r   r   r   r   r   r   r   /jarvis_finance.services.grocery_price_providersr   r   r   r   r   r6   rJ   rL   r   r   r   r   r   r  r  r  r:  r`  rh  rv  ry  rU   r7   r5   <module>r     s   " " " " " "                      R R R R R R R R                            t  t  t  t  t  t  t  t  t  t  t  t  t  t   q q q q q	B 	B 	B 	B 	B+ 	B 	B 	B< < < <&H H H H 7 7 7 7 _ _ _ _b b b b3 3 3 3(, , , ,	i 	i 	i 	i* * * *4 4 4 4$ $ $ $> > > >"
> 
> 
> 
> 
> 
>r7   