Ë
    §‘ˆjX  ã                   óV  — d Z ddlZddlZddlZ ej                  e«      ZdZdZi 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d“dd“dd“dd“Z	d e
d!e
fd"„Z G d#„ d$e«      Zd%„ Zd&ed!efd'„Zd&ed(e
d!efd)„Zd*e
fd+„Zd*e
fd,„Zd*e
fd-„Z	 d2d.e
d/e
d0e
d!eee   ee   f   fd1„Zy)3a  Turns a Shopify-format product CSV into source products.

Pure: no database, no network, no request objects, so every grouping and
validation rule is testable without a fixture. The output is the same shape the
Shopify and HTTP connectors emit, so normalise() takes it unchanged.
é    N)ÚHandleÚTitleÚdescriptionúBody (HTML)ÚbrandÚVendorÚcategoryÚTypeÚskuzVariant SKUÚquantityúVariant Inventory QtyÚstockÚpriceúVariant Pricezcompare at priceúVariant Compare At Pricez	image urlú	Image SrcÚimagez
url handler   ÚurlúProduct URLzproduct urlÚlinkÚoption1zOption1 ValueÚoption2zOption2 ValueÚnameÚreturnc                 ó`   — t        | «      }t        j                  |j                  «       |«      S )z9A CSV header under the name the rest of this module uses.)Ú_cleanÚCOLUMN_ALIASESÚgetÚlower)r   Úcleaneds     ú>/var/www/html/strategist-ai/app/services/catalog/csv_source.pyÚcanonical_headerr"   +   s$   € ä�T‹l€GÜ×Ñ˜gŸm™m›o¨wÓ7Ð7ó    c                   ó   — e Zd ZdZy)ÚCsvFormatErrorzFThe file cannot be read at all. Row problems are reported, not raised.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© r#   r!   r%   r%   1   s   „ ÚPr#   r%   c                 ó*   — | xs dj                  «       S )NÚ )Ústrip)Úvalues    r!   r   r   5   s   € ØŠK�R×ÑÓ Ð r#   Úrowc                 ó¦   — i }dD ]I  }t        | j                  d|› d�«      «      }t        | j                  d|› d�«      «      }|sŒB|sŒE|||<   ŒK |S )N)é   é   é   ÚOptionz Namez Value)r   r   )r/   ÚoptionsÚindexr   r.   s        r!   Ú_optionsr7   9   sc   € Ø€GØò "ˆÜ�c—g‘g  u g¨UÐ3Ó4Ó5ˆÜ�s—w‘w ¨ w¨fÐ5Ó6Ó7ˆÚ’EØ!ˆG�DŠMð	"ð
 €Nr#   Úproduct_urlc                 ó¦   — t        | j                  d«      «      }t        | j                  d«      «      xs |}|r|sg S ddlm} || |||«      dœgS )aä  The button a shopper presses, if the merchant supplied one.

    Same shape the crawler produces -- label, url, type -- so a card renders
    identically whether the product came from a spreadsheet or a page. The type
    is inferred from the label the way it is for a scraped button, rather than
    asking a merchant to learn a vocabulary.

    A label with no URL falls back to the product's own page: a button that
    goes nowhere is worse than one that goes to the product.
    zCTA TextzCTA URLr   )Ú_classify_cta)Úlabelr   Útype)r   r   Ú'app.services.content.product_extractionr:   )r/   r8   r;   r   r:   s        r!   Ú_ctar>   C   sV   € ô �3—7‘7˜:Ó&Ó'€EÜ
�—‘˜Ó#Ó
$Ò
3¨€CÙ™Øˆ	õ Fà C±¸sÀEÓ1JÑKÐLÐLr#   Úrawc                 ó†   — t        | «      }|sy	 t        |«      }|dk  rdd|›d�fS |dfS # t        $ r dd|›d�fcY S w xY w)z3Returns (price, reason). reason is None on success.)NzVariant Price is requiredNzVariant Price ú is not a numberr   ú cannot be negative©r   ÚfloatÚ
ValueError)r?   r.   r   s      r!   Ú_parse_pricerF   \   sp   € ä�3‹K€EÙØ0ð@Ü�e“ˆð ˆq‚yØ�~ e YÐ.AÐBÐBÐBØ�$ˆ;Ðøô	 ò @Ø�~ e YÐ.>Ð?Ð?Ò?ð@ús   �, ¬A ¿A c                 ó˜   — t        | «      }|sy	 t        t        |«      «      }|dk  rdd|›d�fS |dfS # t        $ r dd|›d�fcY S w xY w)z@Returns (quantity, reason). Blank means untracked, treated as 0.)r   NNzVariant Inventory Qty rA   r   rB   )r   ÚintrD   rE   )r?   r.   r   s      r!   Ú_parse_quantityrI   j   sw   € ä�3‹K€EÙØðHÜ”u˜U“|Ó$ˆð �!‚|ØÐ-¨e¨YÐ6IÐJÐJÐJØ�Tˆ>Ðøô	 ò HØÐ-¨e¨YÐ6FÐGÐGÒGðHús   �5 µA	ÁA	c                 óT   — t        | «      }|sy 	 t        |«      S # t        $ r Y y w xY w©NrC   )r?   r.   s     r!   Ú_compare_at_pricerL   x   s2   € Ü�3‹K€EÙØðÜ�U‹|ÐøÜò Ùðús   �
 ›	'¦'ÚtextÚ
source_refÚcurrencyc                 óV  — t        |«      xs d }| r| j                  «       st        d«      ‚t        j                  t        j                  | «      «      }|j                  xs g D �cg c]  }t        |«      ‘Œ }}t        D �cg c]	  }||vsŒ|‘Œ }}|rt        ddj                  |«      › �«      ‚t        |d¬«      D ��	�
�cg c]4  \  }}	||	j                  «       D �
�ci c]  \  }
}t        |
«      |“Œ c}}
f‘Œ6 }}
}	}}|st        d«      ‚i }g }|D �]¸  \  }}	t        |	j                  d«      «      }|s|j                  |dd	œ«       Œ8t        |	j                  d
«      «      \  }}|r|j                  ||d	œ«       Œlt!        |	j                  d«      «      \  }}|r|j                  ||d	œ«       Œ |j                  |«      }|�€Ät        |	j                  d«      «      }|s|j                  |dd	œ«       Œåt        |	j                  d«      «      }|r>|j#                  d«      D �cg c]#  }|j                  «       sŒ|j                  «       ‘Œ% c}ng }i d|“d|“dt        |	j                  d«      «      xs d “dt        |	j                  d«      «      xs d “d|“dt        |	j                  d«      «      xs d “dt        |	j                  d«      «      xs d “dd “dt        |	j                  d«      «      xs d “d|“dg “d t        |	j                  d!«      «      xs d “d"d#“d$g “d%g “d&t%        |	t        |	j                  d«      «      «      “d'd(“|i d d d t        |	j                  d)«      «      j'                  «       xs |d*œ¥}|||<   |d$   j                  |t)        |	j                  d+«      «      |t*        k7  t-        |	«      d,œ«       �Œ» |r t.        j1                  d-|t3        |«      «       t5        |j7                  «       «      |fS c c}w c c}w c c}}
w c c}}
}	}w c c}w ).Nzfile is emptyzmissing required column(s): z, r2   )Ústartzfile has no data rowsr   zHandle is required)r/   Úreasonr   r   r   z)Title is required on a handle's first rowÚTagsÚ,Úexternal_idÚtitler   r   r   r   Úhandler8   r   Ú	image_urlr   Úraw_categoryÚproduct_typer
   ÚtagsÚcollectionsÚstatusÚStatusÚtracks_inventoryTÚvariantsÚattributes_rawÚctasÚsource_kindÚcsvÚCurrency)rN   Útenant_relationsÚratingÚreview_countÚfeatured_rankrO   r   )r   Úcompare_at_priceÚ	availabler5   zcsv import %s: %d row error(s))r   r-   r%   rd   Ú
DictReaderÚioÚStringIOÚ
fieldnamesr"   ÚREQUIRED_COLUMNSÚjoinÚ	enumerateÚitemsr   ÚappendrF   rI   Úsplitr>   ÚupperrL   Ú_OUT_OF_STOCK_QTYr7   ÚloggerÚwarningÚlenÚlistÚvalues)rM   rN   rO   ÚreaderÚfro   ÚcÚmissingÚnumberr/   ÚkÚvÚrowsÚproductsÚerrorsÚ
row_numberrW   r   Úprice_errorr   Úquantity_errorÚproductrV   Útags_rawÚtr[   s                             r!   Úparse_productsr�   ‚   sH  € ô �hÓÒ' 4€HÙ�t—z‘z”|Ü˜_Ó-Ð-ä�^‰^œBŸK™K¨Ó-Ó.€FØ06×0AÑ0AÒ0GÀRÖI¨!Ô" 1Õ%ÐI€JÐIÜ*ÖB�Q¨a°zÒ.AŠqÐB€GÐBÙÜÐ;¸D¿I¹IÀgÓ<NÐ;OÐPÓQÐQô  )¨°qÔ9÷;ñ ;Ù�˜ð ¸¿¹»×E±°°AÔ& qÓ)¨1Ñ,ÓEÒFð ;€Dó ;áÜÐ4Ó5Ð5à "€HØ€Fàó <‰ˆ
�CÜ˜Ÿ™ Ó)Ó*ˆÙØ�M‰M *Ð8LÑMÔNØä)¨#¯'©'°/Ó*BÓCÑˆˆ{ÙØ�M‰M *¸ÑDÔEØä#2°3·7±7Ð;RÓ3SÓ#TÑ ˆ�.ÙØ�M‰M *¸ÑGÔHØà—,‘,˜vÓ&ˆØ‰?Ü˜3Ÿ7™7 7Ó+Ó,ˆEÙØ—‘ jÐ<gÑhÔiØä˜cŸg™g f›oÓ.ˆHÙLT x§~¡~°cÓ':ÖH !¸a¿g¹g½i�A—G‘G•IÓHÐZ\ˆDðØ˜vðà˜ðð œv c§g¡g¨mÓ&<Ó=ÒEÀðð œ §¡¨Ó 1Ó2Ò:°dð	ð
 ˜&ðð œv c§g¡g¨mÓ&<Ó=ÒEÀðð œV C§G¡G¨KÓ$8Ó9ÒA¸Tðð  ðð ¤ s§w¡w¨v£Ó 7Ò ?¸4ðð ˜ðð ˜rðð œ& §¡¨Ó!2Ó3Ò;°tðð # Dðð ˜Bðð ! "ðð  œ˜S¤&¨¯©°Ó)?Ó"@ÓAð!ð" ˜uð#ð$ )Ø$&ØØ $Ø!%ô # 3§7¡7¨:Ó#6Ó7×=Ñ=Ó?ÒKÀ8ò3ˆGð6  'ˆH�VÑà�
Ñ×"Ñ"ØÜ 1°#·'±'Ð:TÓ2UÓ VØ!Ô%6Ñ6Ü “}ñ	$
ö 	ðo<ñ| Ü�‰Ð7¸ÄSÈÃ[ÔQä�—‘Ó!Ó" FÐ*Ð*ùò] JùÚBùó Fùõ ;ùò@ Is6   Á'PÂ	PÂPÃP
Ã PÃ6P
È)P&È?P&ÐP
rK   )r)   rd   rm   ÚloggingÚ	getLoggerr&   rx   rp   rw   r   Ústrr"   Ú	Exceptionr%   r   Údictr7   r{   r>   rF   rI   rL   Útupler�   r*   r#   r!   ú<module>r”      s³  ðñó Û 	Û à	ˆ×	Ñ	˜8Ó	$€à&Ð ØÐ ðØ�=ðàˆXðð �ðð 
ˆ=ð	ð
 Ð'ðð Ð$ðð ˆ_ðð Ð2ðð �ðð ˆ[ðð �(ðð 
ˆ=ðð  �=ð!ð" ˆMð#ð$ ˆð%ð& ˆð'€ð.8˜3ð 8 3ó 8ôQ�Yô Qò!ð�$ð ˜4ó ðMˆdð M ð M¨ó Mð2�có ð˜ó ð˜3ó ð $(ñY+˜ð Y+¨#ð Y+Ø ðY+Ø,1°$°t±*¸dÀ4¹jÐ2HÑ,IôY+r#   