Ë
    v!ƒjX  ã                  óœ   — d Z ddlmZ ddlZddlZddlmZmZ ddlm	Z	 ddl
mZmZ ddlmZ ddlmZ d	Zd
„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zd„ Zy)z=CSV/Excel bulk upsert helpers for directional freight routes.é    )ÚannotationsN)ÚDecimalÚInvalidOperation)Útransaction)Úis_valid_country_codeÚnormalize_country_code)Úcurrency_code_for_country)ÚFreightRoute)Úorigin_codeÚdestination_codeÚmin_freightc                óf   — | xs dj                  «       j                  «       j                  dd«      S )NÚ Ú Ú_)ÚstripÚlowerÚreplace)Úvalues    ú-/var/www/html/truck-me/core/freight_import.pyÚ_normalize_headerr      s+   € ØŠK�R×ÑÓ ×&Ñ&Ó(×0Ñ0°°cÓ:Ð:ó    c                óz   — dD ]  }	 | j                  |«      c S  | j                  dd¬«      S # t        $ r Y Œ6w xY w)N)z	utf-8-sigúutf-8zlatin-1r   r   )Úerrors)ÚdecodeÚUnicodeDecodeError)Ú	raw_bytesÚencodings     r   Ú_decode_textr       sS   € Ø5ò ˆð	Ø×#Ñ# HÓ-Ò-ðð
 ×Ñ˜G¨IÐÓ6Ð6øô "ò 	Ùð	ús   ‡.®	:¹:c                ó„  — t        | «      }t        j                  t        j                  |«      «      }|j
                  st        d«      ‚|j
                  D �ci c]  }|sŒt        |«      |“Œ }}t        D �cg c]	  }||vsŒ|‘Œ }}|rt        ddj                  |«      › d�«      ‚g }t        |d¬«      D ]{  \  }}	|j                  ||	j                  |d   d«      |	j                  |d	   d«      |	j                  |d
   d«      d|v r"|	j                  |j                  dd«      d«      nddœ«       Œ} |S c c}w c c}w )NzCSV file has no header row.úMissing required columns: ú, ú.é   ©Ústartr   r   r   r   ÚcurrencyÚUSD©Úrowr   r   r   r(   )r    ÚcsvÚ
DictReaderÚioÚStringIOÚ
fieldnamesÚ
ValueErrorr   ÚREQUIRED_COLUMNSÚjoinÚ	enumerateÚappendÚget)
r   ÚtextÚreaderÚhÚheadersÚcolÚmissingÚrowsÚidxr+   s
             r   Ú_rows_from_csvr?       s;  € Ü˜	Ó"€DÜ�^‰^œBŸK™K¨Ó-Ó.€FØ×ÒÜÐ6Ó7Ð7Ø06×0AÑ0AÖG¨1ÂQÔ  Ó# QÑ&ÐG€GÐGÜ.ÖE�s°#¸WÒ2DŠsÐE€GÐEÙÜÐ5°d·i±iÀÓ6HÐ5IÈÐKÓLÐLØ€DÜ˜f¨AÔ.ò ‰ˆˆSØ�‰ØØŸ7™7 7¨=Ñ#9¸2Ó>Ø #§¡¨Ð0BÑ(CÀRÓ HØŸ7™7 7¨=Ñ#9¸2Ó>ØDNÐRYÑDY˜Ÿ™ §¡¨J¸Ó ;¸RÔ@Ð_dñ
õ 	ðð €Kùò HùÚEs   ÁD8Á!D8Á9	D=ÂD=c                óÆ  ‡‡— 	 ddl m}  |t	        j
                  | «      dd¬«      }|j                  }|j                  d¬«      }	 t        |«      }i Št        |«      D ]%  \  }}t        |�t        |«      nd«      }	|	sŒ!|‰|	<   Œ' t        D �
cg c]	  }
|
‰vsŒ|
‘Œ }}
|rt        d	d
j                  |«      › d�«      ‚g }t        |d¬«      D ]Q  \  }Š‰�t        d„ ‰D «       «      rŒdˆˆfd„	}|j!                  | |d«       |d«       |d«       |dd«      dœ«       ŒS |S # t        $ r}t        d«      |‚d }~ww xY w# t        $ r}t        d«      |‚d }~ww xY wc c}
w )Nr   )Úload_workbookz=Excel (.xlsx) import requires openpyxl. Upload a CSV instead.T)ÚfilenameÚ	read_onlyÚ	data_only)Úvalues_onlyzExcel file is empty.r   r"   r#   r$   r%   r&   c              3  ó`   K  — | ]&  }|d u xs t        |«      j                  «       dk(  –— Œ( y ­w©Nr   )Ústrr   )Ú.0Úvs     r   ú	<genexpr>z"_rows_from_xlsx.<locals>.<genexpr>P   s+   è ø€ Ò SÀq  d Ò!B¬c°!«f¯l©l«nÀÑ.BÓ!BÑ Sùs   ‚,.c                ód   •— ‰j                  | «      }|€|S |t        ‰«      k  r‰|   nd }|€dS |S rG   )r6   Úlen)ÚnameÚdefaultr;   r   r:   Úvaluess       €€r   Úcellz_rows_from_xlsx.<locals>.cellS   s@   ø€ Ø—+‘+˜dÓ#ˆCØˆ{Ø�Ø#&¬¨V«Ò#4�F˜3’K¸$ˆEØ˜�2Ð1¨EÐ1r   r   r   r   r(   r)   r*   )r   )ÚopenpyxlrA   ÚImportErrorr1   r.   ÚBytesIOÚactiveÚ	iter_rowsÚnextÚStopIterationr4   r   rH   r2   r3   Úallr5   )r   rA   ÚexcÚworkbookÚsheetÚ	rows_iterÚ
header_rowr>   rQ   Úkeyr;   r<   r=   Úrow_numr:   rP   s                 @@r   Ú_rows_from_xlsxra   5   s�  ù€ ðÝ*ñ ¤b§j¡j°Ó&;ÀtÐW[Ô\€HØ�O‰O€EØ—‘¨D�Ó1€Ið:Ü˜)“_ˆ
ð €GÜ˜zÓ*ò ‰	ˆˆTÜ¨TÐ-=¤ D¤	À2ÓFˆÚØˆG�CŠLðô /ÖE�s°#¸WÒ2DŠsÐE€GÐEÙÜÐ5°d·i±iÀÓ6HÐ5IÈÐKÓLÐLà€DÜ$ Y°aÔ8ò ‰ˆ�Øˆ>œSÑ SÈFÔ SÔSØö	2ð 	�‰ØÙ Ó.Ù $Ð%7Ó 8Ù Ó.Ù˜Z¨Ó/ñ
õ 	ðð$ €KøôS ò ÜØKó
àð	ûðûô ò :ÜÐ/Ó0°cÐ9ûð:üò Fs;   „D$ ÁE Â	EÂEÄ$	D>Ä-D9Ä9D>Å	EÅ
EÅEc                óÈ   — t        | dd«      xs dj                  «       }| j                  «       }|st        d«      ‚|j	                  d«      rt        |«      S t        |«      S )z6Return normalized row dicts from a CSV or XLSX upload.rN   r   zUploaded file is empty.)z.xlsxz.xlsm)Úgetattrr   Úreadr1   Úendswithra   r?   )Úuploaded_filerN   Úraws      r   Úparse_freight_route_uploadrh   d   s^   € ä�M 6¨2Ó.Ò4°"×;Ñ;Ó=€DØ
×
Ñ
Ó
€CÙÜÐ2Ó3Ð3Ø‡}�}Ð'Ô(Ü˜sÓ#Ð#Ü˜#ÓÐr   c                óŽ   — t        | «      }|s5t        | xs d«      j                  «       xs d}t        | «      sd d|› d�fS y|d fS )Nr   z(empty)z!Unknown or invalid country code: r$   )NzCountry code is required.)r   rH   r   r   )rg   ÚcodeÚraw_displays      r   Ú_parse_country_coderl   o   sT   € Ü! #Ó&€DÙÜ˜#š) “n×*Ñ*Ó,Ò9°	ˆÜ$ SÔ)ØÐ<¸[¸MÈÐKÐKÐKØ0Ø�ˆ:Ðr   c                ó¸   — t        | �| nd«      j                  «       j                  dd«      }|sy	 t        |«      }|dk  ry|d fS # t        t
        f$ r Y yw xY w)Nr   Ú,)Nzmin_freight is required.)Nz#min_freight must be a valid number.r   )Nzmin_freight cannot be negative.)rH   r   r   r   r   r1   )rg   r   Úamounts      r   Ú_parse_min_freightrp   y   sk   € Ü�s�‘¨BÓ/×5Ñ5Ó7×?Ñ?ÀÀRÓH€EÙØ/ð;Ü˜“ˆð �‚zØ6Ø�4ˆ<Ðøô	 œjÐ)ò ;Ù:ð;ús   ²A ÁAÁAc           	     óÜ  — d}d}g }| D �]›  }|j                  d«      }	 t        |j                  d«      «      \  }}|r|j                  ||dœ«       ŒJt        |j                  d«      «      \  }}	|	r|j                  ||	dœ«       Œ~||k(  r|j                  |ddœ«       Œ˜t        |j                  d«      «      \  }
}|r|j                  ||dœ«       ŒÌt	        |j                  d«      xs d	«      j                  «       j                  «       }|r7t        |«      d
k7  s|j                  «       s|j                  |ddœ«       �Œ<|}nt        |«      }t        j                  «       5  t        j                  j                  |||
|dœ¬«      \  }}ddd«       r|dz  }n|dz  }�Œž |||dœS # 1 sw Y   ŒxY w# t        $ r(}|j                  |t	        |«      dœ«       Y d}~�ŒÝd}~ww xY w)z§
    Upsert routes from normalized rows.
    Returns {created, updated, errors: [{row, message}]}.
    Country codes must exist in core.countries.COUNTRY_BY_CODE.
    r   r+   r   )r+   Úmessager   z3Origin and destination must be different countries.r   r(   r   é   z%currency must be a 3-letter ISO code.)r   r(   )Úorigin_country_codeÚdestination_country_codeÚdefaultsNé   )ÚcreatedÚupdatedr   )r6   rl   r5   rp   rH   r   ÚupperrM   Úisalphar	   r   Úatomicr
   ÚobjectsÚupdate_or_createÚ	Exception)r=   rx   ry   r   Úitemr`   ÚoriginÚ
origin_errÚdestinationÚdest_errr   Úfreight_errÚraw_currencyr(   ÚrouteÚwas_createdrZ   s                    r   Úbulk_upsert_freight_routesr‰   †   sÿ  € ð €GØ€GØ€Fàó ,AˆØ—(‘(˜5“/ˆð*	AÜ!4°T·X±X¸mÓ5LÓ!MÑˆF�JÙØ—‘ g¸*ÑEÔFØÜ$7¸¿¹ÐASÓ8TÓ$UÑ!ˆK˜ÙØ—‘ g¸(ÑCÔDØØ˜Ò$Ø—‘Ø"ØTñô ð Ü'9¸$¿(¹(À=Ó:QÓ'RÑ$ˆK˜ÙØ—‘ g¸+ÑFÔGØÜ˜tŸx™x¨
Ó3Ò9°rÓ:×@Ñ@ÓB×HÑHÓJˆLÙÜ�|Ó$¨Ò)°×1EÑ1EÔ1GØ—M‘M¨'Ð>eÑ"fÔgÙØ'‘ä4°VÓ<�ä×#Ñ#Ó%ñ Ü%1×%9Ñ%9×%JÑ%JØ(.Ø-8à'2Ø$,ñð &Kó &Ñ"��{÷ñ Ø˜1‘‘à˜1‘�ùðU,Að^ ØØñð ÷!ð ûô ò 	AØ�M‰M '´c¸#³hÑ?×@Ò@ûð	AúsN   Ÿ3F:Á3F:ÂF:Â!3F:ÃA.F:Å"F:Å')F.ÆF:Æ.F7	Æ3F:Æ:	G+ÇG&Ç&G+)Ú__doc__Ú
__future__r   r,   r.   Údecimalr   r   Ú	django.dbr   Úcore.countriesr   r   Úcore.currenciesr	   Úcore.modelsr
   r2   r   r    r?   ra   rh   rl   rp   r‰   © r   r   ú<module>r’      sR   ðÙ Cå "ã 
Û 	ß -å !ç HÝ 5Ý $ð FÐ ò;ò7òò*,ò^òò
ó<r   