
    "GjH@                        d Z ddlZddlZddlZddlmc mZ ddlm	Z	 ddl
mZmZmZ ddlZddlmZ ddlmZmZmZ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! de	d	e"d
e	fdZ#de"dz  d
e$fdZ% ej&        d          Z' ej&        d          Z(de"fdZ)de"d
ej*        fdZ+dej,        d
ej*        fdZ-de	d
ej*        fdZ.de	d
ej*        fdZ/dej*        de	d
dfdZ0dee"ej*        f         de	d
dfdZ1 G d de          Z2 G d  d!e          Z3e4d"k    rR eej5                  Z6 e3            Z7e78                                  ej9        e6:                                           dS dS )#u  
Windows-Desktop-Tool (PyQt5) zum lokalen Umwandeln von *.crbx* / SIA 451 / E1S / 01S
in strukturierte Excel-Listen inkl. Preisspiegel.

• Robustes E1S/01S-Parsing (Whitespace / Semikolon / Fixed-Width, mit führenden Nummern wie "000 P …")
• XML (IfA18/SIA 451) mit oder ohne Namespace
• Bereits konvertierte .xlsx mit Mapping (Header in Zeile 3)
• Drag & Drop + Dateidialog
• Ausgabe im selben Ordner; Versions-Hochzählen bei Kollision
• Preisspiegel je NPK (Aggregation)
    NPath)DictListOptional)Qt)QPixmapQBrushQPaletteQDragEnterEvent
QDropEvent)	QApplicationQMainWindowQWidgetQVBoxLayoutQLabelQPushButtonQFileDialogQMessageBox
QStatusBarsrcsuffixreturnc                    | j         r*|                     d          }| j        }||j        |z   z  }n'| j        }|| j        |z   z                      d          }d}|                                rd|j        |j         }}d|v r|d|                    d                   }|                    | d| |           }|dz  }|                                d|S )z;Erzeuge eindeutigen Ausgabepfad im gleichen Ordner wie src. .xlsx   _vN   )r   with_suffixparentnameexistsstemrfind	with_name)r   r   basefolder	candidateir$   exts           main.pysafe_out_pathr-   !   s    
z Hr""di&01		sx&01>>wGG		A




 NI$4c4<<)D)))*D''4(;(;1(;c(;(;<<		Q 



      txtc                    | dS t          |                               dd                              dd                              dd                              dd                                          }|                    d          d	k    r/|                    d
          dk    r|                    dd
          }t	          |          dk    rQ|d                                         s7|dd         }t	          |          dk    r|d                                         7	 t          |          S # t          $ r Y dS w xY w)zHNormalisiert CH/DE/FR-Zahlen (Apostroph-Tausender, NBSP, Dezimal-Komma).N             u    'r   ,r   .r   )strreplacestripcountlenisdigitfloat
ValueError)r/   ss     r,   
_to_numberrA   4   s   
{sC	3			3			b			b			  	wws||qQWWS\\Q..IIc3
a&&1**QrU]]__*crcF a&&1**QrU]]__*Qxx   sss   #D2 2
E ?E uY   ^[\s0-9]*P\s+(\S+)\s+([0-9\-\+\s',\.]+)\s+([A-Za-z0-9%°/]+)\s+([0-9\-\+\s',\.]+)\s+(.*)$z^^[\s0-9]*P\s*;\s*([^;]+)\s*;\s*([^;]*)\s*;\s*([^;]*)\s*;\s*([^;]+)\s*;\s*([^;]+)\s*;\s*([^;]+)linec                    t          j        d|           }|sdS | |                                d         }t          |          dk     rdS |dd                                         }t          |dd                   }|dd                                         }t          |dd                   }|dd                                         }|sdS |||||fS )u}   Fallback: Fixed-Width nach häufigem E1S-Schema.
    Erwartet, dass `line` irgendwo ein 'P' enthält; wir schneiden davor ab.z[Pp]N.            "   )researchstartr<   r:   rA   )rB   mr'   npkqtyunitpricetexts           r,   
_try_fixedrR   R   s     		'4  A t		

D
4yy2~~t2JCtBrE{##CBKDtBrE{##EIOOD tT5$&&r.   contentc           
      ,   g }dx}x}}dx}}|                                  D ]}|t          |                              d                              d          }|                                sPt          j        d|          }	|	sh|	                    d                                          }
|
dk    r|dz  }d}t                              |          }|r|                    d                                          }|                    d	          pd
                                }t          |                    d                    }|                    d                                          }t          |                    d                    }|}|||||f}|t                              |          }|r|                    d                                          }t          |                    d	                    }|                    d                                          }t          |                    d                    }|                    d          pd
                                }|||||f}|t          |          }|r|\  }}}}}|                    |||||||z  d           |
dk    rq|dz  }t          j        d|          }|s|                    d          }t          |                    d	                    }|dk    r|} |dk    r|}
|dk    r|}t          j        |          }|j        rt%          d| d| d          g }|r|                    ddd
d
d
| d           |r|                    ddd
d
d
|d           |r|n&t'          |d                                                   }|                    ddd
d
d
|d           t          j        |t          j        |          gd           S )!u  
    Robustes E1S/01S-Parsing:
     • toleriert BOM & Einrückung sowie führende Ordnungszahlen (z.B. "000 P …")
     • erkennt Whitespace-, Semikolon- und Fixed-Width-Format
     • versteht CH/DE-Zahlenformate
     • liest C070 (Rabatt), C099 (MwSt), C998 (Total)
    r1   r   Nu   ﻿z
z^[\s0-9]*([A-Za-z])r   Pr   r         rE      NPKKurztextMengeEinheitEinzelpreisGesamtCz8^[\s0-9]*C(\d{3}).*?([-+]?\d[\d\s'\u00A0\u202F\.,]*)\s*$070099998z3Keine Positionen in E1S erkannt (P-Zeilen gesehen: z, C-Zeilen gesehen: z.). Das Layout weicht von bekannten Mustern ab.RabattRabattbetragMwStMehrwertsteuerr_   TotalzEndsumme inkl. MwStTignore_index)
splitlinesr8   lstriprstripr:   rI   matchgroupupper_RX_SCrA   _RX_WSrR   appendrJ   pd	DataFrameemptyr?   r>   sumconcat)rS   recordsrabattmwsttotal
cnt_p_seen
cnt_c_seenrawrB   mtypetrecm_scrM   kurzrN   rO   rP   rQ   m_wsmengeeinheitpreisrL   codeamtdfsummary	total_vals                                r,   parse_e1s_textr   h   s    GFTEJ!!## 9 9;3xxx((//77zz|| 	/66 	KKNN  ""88!OJC<<%%D 4jjmm))++

1+2244 A//zz!}}**,,"4::a==11Cud3{||D)) 8 JJqMM//11C&tzz!}}55C JJqMM//11D&tzz!}}55E!ZZ]]0b7799DT5$7C{ &&{/2,CNN "$%-      #XX!OJ	UW[\\A 771::Daggajj))Cu}}	g		B	x 
:* : :bl : : :
 
 	
 G Hx^b]_pr  @F  F  G  G  	H  	H  	H Ev3Cb]_pr  C  D  D  	E  	E  	E=E"X,*:*:*<*<$=$=INN70EPR_art  AJ  K  K  L  L  L9b",w//0tDDDDr.   rootc           
      j   | j         }d|v r|                    d          d                             d          dt          dt          ffdddt          j        d	t          d
t          dt          ffd}|                      d                    }nXdt          dt          fdddt          j        d	t          d
t          dt          ffd}|                      d                    }g }|D ]}|                     d                    pd                                }|                     d                    pd                                }t           ||dd          	                    dd                    }t           ||dd          	                    dd                    }	|                     d                    pd                                }
|
                    ||||
|	||	z  d           t          j        |          }|j        rt          d          |S )z1Parst IfA18/SIA451-XML (mit oder ohne Namespace).}r   {xnamer   c                     d d|  S )Nz.//{r    )r   ns_uris    r,   xpzparse_xml_root.<locals>.xp   s    *C&*C*CE*C*C#Cr.   0elr"   defaultc                 D    |                       |                    p|S Nfindtextr   r"   r   r   s      r,   ftextzparse_xml_root.<locals>.ftext   "    ;;rr$xx((3G3r.   Positionc                     d|  S )Nz.//r   )r   s    r,   r   zparse_xml_root.<locals>.xp   s    ---#7r.   c                 D    |                       |                    p|S r   r   r   s      r,   r   zparse_xml_root.<locals>.ftext   r   r.   CatalogueNumberr   	ShortTextQuantityr3   PriceUnitrY   z$Keine Positionen im XML-LV gefunden.)r   )tagsplitr:   r8   ETElementfindallr   rA   r9   rs   rt   ru   rv   r?   )r   r   r   	positionsrowsposrM   r   r   r   einhr   r   r   s               @@r,   parse_xml_rootr      sp   
(C
czz3"((--CcCcCCCCCC	4 	4bj 	4 	4c 	4C 	4 	4 	4 	4 	4 	4LLJ00		7c7c7777	4 	4bj 	4 	4c 	4C 	4 	4 	4 	4 	4 	4LLJ00	D 	 	RR 122339r@@BBRR__--3::<<55j#66>>sBGGHH55gs33;;CDDEEbbjj))/R6688D5EUU]
 
 	 	 	 	
 
d		B	x A?@@@Ir.   pathc                     t          j        t          |           d          ddddddd	d
ddd
}                    |          g d}fd|D             }|rt	          d|           |         S )Nr   )headerrZ   r[   Langtextr\   r]   r^   r_   rd   PreisNachNachlassrf   )
Ordnungszahlr[   r   r\   r]   EinheitspreisGesamtpreisNachlasszPreis nach NachlasszMwSt.columnsrY   c                 &    g | ]}|j         v|S r   r   ).0cr   s     r,   
<listcomp>z(parse_excel_template.<locals>.<listcomp>   s%    :::Qarz&9&9q&9&9&9r.   zExcel ohne notwendige Spalten: )rt   
read_excelr8   renamer?   )r   mappingrequiredmissingr   s       @r,   parse_excel_templater      s    	s4yy	+	+	+B&2 G 
7	#	#BOOOH::::(:::G FD7DDEEEh<r.   c                    | j                                         }|dk    rt          |           S |dv r	 t          j        t          |                                                     }t          |          S # t          j        $ rQ 	 | 	                    d          }n'# t          $ r | 	                    dd          }Y nw xY wt          |          cY S w xY wt          j        |           rt          j        |           5 }|                                }|D ]}|                                }|                    d          r\	 |                    |          }t          j        |          }t          |          c cd d d            S # t          j        $ r Y w xY w|D ]}|                                }|                    d	          r	 |                    |                              d          }	n:# t          $ r- |                    |                              dd
          }	Y nw xY wt          |	          c cd d d            S 	 d d d            n# 1 swxY w Y   t)          d          t)          d          )Nr   >   .01s.xml.sia451cp1252)encodingzutf-8ignore)r   errors)r   r   r   ).e1sr   )r   z"Keine LV-Daten im Archiv gefunden.zUnbekanntes Dateiformat.)r   lowerr   r   parser8   getrootr   
ParseError	read_textUnicodeDecodeErrorr   zipfile
is_zipfileZipFilenamelistendswithread
fromstringdecoder?   )
r   r+   r   rQ   zfnamesnlndatarS   s
             r,   
parse_pathr      s*   
+



C
g~~#D)))
)))	(8CII&&..00D!$'''} 	( 	( 	(I~~x~88% I I I~~wx~HHI!$'''''	( $ ?_T"" 	3bKKMME ! !WWYY;;:;; !!!wwqzz!}T22-d3333	3 	3 	3 	3 	3 	3 	3 	3 = ! ! ! !!  3 3WWYY;;/00 3N"$''!**"3"3H"="=- N N N"$''!**"3"3GH"3"M"MN)'2222)	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* =>>>
/
0
00s   AA6 6CBC!C>C CCCAI7F<IFIF1I(G87I84H/,I.H//III!$I!r   out_pathc                 R   t          j        t          |          d          5 }|                     |dd           t          j        dt          | d                                                   ig                              |dd           d d d            d S # 1 swxY w Y   d S )	Nopenpyxl)engineF
Positionenindex
sheet_namerh   r_   Zusammenfassung)rt   ExcelWriterr8   to_excelru   r>   rw   )r   r   ws      r,   write_offer_excelr     s    	Hj	9	9	9 
Q
AU|<<<
wbl&6&6&8&8 9 9:;<<EEU'8 	F 	
 	
 	

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
s   A+BB #B dfsc                 4   d }|                                  D ]f\  }}|                    dd          d                                                             d|i          }||n|                    |dd          }g|t          d          |                    d	d
           d |                                  D             }t          j        |t          j	        ddi|g          gd
          }|
                    t          |          dd           d S )NrZ   F)as_indexr_   r   outer)onhowu   Keine Daten für Preisspiegel.r   T)inplacec                 d    i | ]-\  }}|t          |d                                                    .S )r_   )r>   rw   )r   r"   r   s      r,   
<dictcomp>z&build_preisspiegel.<locals>.<dictcomp>/  s6    JJJ($dE"X,**,,--JJJr.   rh   ri   Preisspiegelr   )itemsgroupbyrw   r   merger?   fillnart   rx   ru   r   r8   )r   r   mergedr"   r   grptotalss          r,   build_preisspiegelr  '  s   %)FIIKK U Ubjjj//9==??FFPXZ^O_F``FLLGL,T,T~9:::
MM!TM"""JJciikkJJJFYug.H.H-I J JKZ^___F
OOCMM>OJJJJJr.   c                   6     e Zd Z fdZdefdZdefdZ xZS )	DropLabelc                     t                                          d           |                     t          j                   |                     d           |                     d           || _        d S )NzEDateien hierher ziehen
(.crbx / .e1s / .01s / .xml / .sia451 / .xlsx)Tz5border:2px dashed #888; padding:40px; font-size:16px;)super__init__setAlignmentr   AlignCentersetAcceptDropssetStyleSheetmain)selfr!   	__class__s     r,   r	  zDropLabel.__init__8  sf    abbb".)))D!!!RSSS			r.   ec                 ~    |                                                                 r|                                 d S d S r   )mimeDatahasUrlsacceptProposedAction)r  r  s     r,   dragEnterEventzDropLabel.dragEnterEvent?  s@    ::<<!! 	%""$$$$$	% 	%r.   c                     d |                                                                 D             }| j                            |           d S )Nc                 P    g | ]#}t          |                                          $S r   )r   toLocalFile)r   us     r,   r   z'DropLabel.dropEvent.<locals>.<listcomp>D  s(    DDD1ammoo&&DDDr.   )r  urlsr  process_files)r  r  filess      r,   	dropEventzDropLabel.dropEventC  sE    DD

0A0A0C0CDDD	&&&&&r.   )	__name__
__module____qualname__r	  r   r  r   r  __classcell__r  s   @r,   r  r  7  sn            % % % % %': ' ' ' ' ' ' ' 'r.   r  c                   <     e Zd Z fdZd Zdee         fdZ xZS )
MainWindowc                 b   t                                                       |                     d           |                     dd           t	          d          }|                                rt          t          |                    }|                                 }|	                    t          j        t          |                     |                     |           |                     d           t                      }t!          |          }t#          |           | _        |                    | j                   t)          d| j                  }|                    |           |                     |           t/                      | _        |                     | j                   d S )Nu   CRBX → XLSX Converteri   iX  zresources/placeholder.pngTu   Dateien auswählen …)clicked)r  r	  setWindowTitlesetFixedSizer   r#   r	   r8   palettesetBrushr   Windowr
   
setPalettesetAutoFillBackgroundr   r   r  drop	addWidgetr   open_dialogsetCentralWidgetr   statussetStatusBar)r  bgpixpalcentralvboxbtnr  s          r,   r	  zMainWindow.__init__I  s^   5666#s###-..99;; 	-#b''""C,,..CLL&++666OOC   &&t,,,))7##dOO	ty!!!2D<LMMMsg&&& ll$+&&&&&r.   c                     t          j        | ddd          \  }}|r!|                     d |D                        d S d S )Nu   Dateien wählenr   zGCRBX/E1S/01S/XML/XLSX/SIA451 (*.crbx *.e1s *.01s *.xml *.xlsx *.sia451)c                 ,    g | ]}t          |          S r   r   )r   fs     r,   r   z*MainWindow.open_dialog.<locals>.<listcomp>h  s    777AQ777r.   )r   getOpenFileNamesr  )r  r  _s      r,   r1  zMainWindow.open_dialog`  sa    /U	
 
q  	97777788888	9 	9r.   pathsc                 :   h dfd|D             }|st          j        | dd           d S i }g }|D ]}| j                            d|j         d           	 t          |          }t          |d          }t          ||           |||j        <   `# t          $ r)}|
                    |j         d|            Y d }~d }~ww xY wt          |          d	k    ra|d
         j        }	t          |	dz  d          }
	 t          ||
           n/# t          $ r"}|
                    d|            Y d }~nd }~ww xY w| j                            d           |r+t          j        | dd                    |                     d S t          j        | dd           d S )N>   .crbxr   r   r   r   r   c                 J    g | ]}|j                                         v | S r   )r   r   )r   p	valid_exts     r,   r   z,MainWindow.process_files.<locals>.<listcomp>l  s/    CCCqQX^^%5%5%B%B%B%B%Br.   Hinweisu'   Bitte unterstützte Dateien auswählen.zVerarbeite u    …z_converted.xlsxz: r   r   
Auswertungz_Preisspiegel.xlsxzPreisspiegel: zFertig.u   Abgeschlossen – mit Hinweisen
ErledigtzUmwandlung abgeschlossen!)r   warningr3  showMessager"   r   r-   r   r$   	Exceptionrs   r<   r!   r  joininformation)r  r@  validr   r   rD  r   outexfirst_folderps_pathrE  s              @r,   r  zMainWindow.process_filesj  s   III	CCCCECCC 	i1Z[[[F') 	1 	1AK##$>!&$>$>$>???1]]#A'899!"c*** AF 1 1 1//2//000000001 s88a<< 8?L#L<$?AUVVG5"30000 5 5 53r33444444445 		*** 	S&GSYIZIZ[[[[[#D*6QRRRRRs0   9B
CCC>D 
D;D66D;)	r  r   r!  r	  r1  r   r   r  r"  r#  s   @r,   r%  r%  H  so        ' ' ' ' '.9 9 9 S4:  S  S  S  S  S  S  S  Sr.   r%  __main__);__doc__rI   sysr   xml.etree.ElementTreeetreeElementTreer   pathlibr   typingr   r   r   pandasrt   PyQt5.QtCorer   PyQt5.QtGuir	   r
   r   r   r   PyQt5.QtWidgetsr   r   r   r   r   r   r   r   r   r8   r-   r>   rA   compilerr   rq   rR   ru   r   r   r   r   r   r   r  r  r%  r  argvappwinshowexitexec_r   r.   r,   <module>rg     s  
 
 
			 



  " " " " " " " " "       ' ' ' ' ' ' ' ' ' '           N N N N N N N N N N N N N N                     t S T    &C$J 5    . 
`
 
 
e
 
'S ' ' ' ',TEC TEBL TE TE TE TEn     Bt     ,&1T &1bl &1 &1 &1 &1R
", 
$ 
4 
 
 
 

KDbl!23 
Kt 
K 
K 
K 
K 
K ' ' ' ' ' ' ' '"BS BS BS BS BS BS BS BSP z
,sx
 
 C
*,,CHHJJJCHSYY[[	 r.   