#include #include #include #include #include #include #include ; ========================================================= ; INDUSTRIAL AUTOIT REB 23.003 → GAEB X31 ENGINE ; kompatibel mit DATAflor / California / GAEB DA XML ; ========================================================= Global $INPUT_FILE = @ScriptDir & "\..\Liebenau_BA_5_Mengennachweiß_AZ002_.txt" Global $OUTPUT_FILE = @ScriptDir & "\..\export2.x31" ; Globaler ID-Zähler für XML-IDs (muss vor Func-Aufrufen deklariert sein) ; Globaler ID-Zaehler (vor allen Local-Deklarationen) Global $g_iIDCnt = 1000000 ; ── Einstiegspunkt ────────────────────────────────────────── Local $importPfadTxt = @ScriptDir & "\..\Meckenbeueren_AZ10_.txt" Local $ausgabePfadX31 = @ScriptDir & "\..\Meckenbeueren_AZ10_x31neu.x31" Local $exportExcelCalifornia = @ScriptDir & "\..\Meckenbeueren_AZ10_.xlsx" ;~ Local $importPfadTxt = @ScriptDir & "\..\FTTx_Achberg_AZ001_.txt" ;~ Local $ausgabePfadX31 = @ScriptDir & "\..\FTTx_Achberg_AZ001_x31neu.x31" ; Beispiel Aufruf _REB_TXT_to_Excel($importPfadTxt,$exportExcelCalifornia) ;~ _X31_Export($importPfadTxt, $ausgabePfadX31) Func _replaceKom2Punkt($sString) Return StringReplace($sString, ",", ".") EndFunc ;==>_replaceKom2Punkt Func _replacePunkt2Koma($sString) Return StringReplace($sString, ".", ",") EndFunc ;==>_replacePunkt2Koma Func _REB_TXT_to_Excel($sTXT, $sExcel) Local $aLines _FileReadToArray($sTXT, $aLines) Local $Baustelle = "" Local $Datum = "" Local $Abschnitt = "" Local $inHeader = False Local $inData = False ; Kopf auslesen For $i = 1 To $aLines[0] Local $line = $aLines[$i] If StringInStr($line, "[Kopfdaten]") Then $inHeader = True ContinueLoop EndIf If StringInStr($line, "[Aufmaßdaten]") Then $inHeader = False $inData = True ExitLoop EndIf If $inHeader Then If StringLeft($line, 9) = "Baustelle" Then $Baustelle = StringTrimLeft($line, 10) EndIf If StringLeft($line, 5) = "Datum" Then $Datum = StringTrimLeft($line, 6) EndIf If StringLeft($line, 13) = "Bauabschnitt=" Then $Abschnitt = StringTrimLeft($line, 13) EndIf EndIf Next ; Excel starten Local $oExcel = _Excel_Open() Local $oBook = _Excel_BookNew($oExcel) ; Kopf schreiben _Excel_RangeWrite($oBook, Default, "Bauvorhaben", "A2") _Excel_RangeWrite($oBook, Default, $Baustelle, "C2") _Excel_RangeWrite($oBook, Default, "Leistungsverzeichnis", "A3") _Excel_RangeWrite($oBook, Default, $Abschnitt, "C3") _Excel_RangeWrite($oBook, Default, "Aufmaß", "A4") _Excel_RangeWrite($oBook, Default, $Datum, "D4") ; Spaltenüberschrift ;~ _Excel_RangeWrite($oBook, Default, "OZ", "A7") ;~ _Excel_RangeWrite($oBook, Default, "Position", "B7") ;~ _Excel_RangeWrite($oBook, Default, "Abschnitt", "C7") ;~ _Excel_RangeWrite($oBook, Default, "Faktor", "D7") ;~ _Excel_RangeWrite($oBook, Default, "REB Formel", "E7") ;~ _Excel_RangeWrite($oBook, Default, "Ergebnis", "F7") Local $row = 7 $inData = False For $i = 1 To $aLines[0] Local $line = $aLines[$i] If StringInStr($line, "[Aufmaßdaten]") Then $inData = True ContinueLoop EndIf If $inData = False Then ContinueLoop If StringStripWS($line, 8) = "" Then ContinueLoop Local $f = StringSplit($line, "|") If $f[0] < 10 Then ContinueLoop Local $Ort = $f[1] Local $OZ = $f[2] Local $Formel = $f[3] Local $Ergebnis = $f[7] Local $Text = $f[9] ; Zeile 1 (Bemerkung) _Excel_RangeWrite($oBook, Default, $OZ, "A" & $row) _Excel_RangeWrite($oBook, Default, $Text, "B" & $row) _Excel_RangeWrite($oBook, Default, $Ort, "C" & $row) $row += 1 ; Zeile 2 (Formel) _Excel_RangeWrite($oBook, Default, $OZ, "A" & $row) _Excel_RangeWrite($oBook, Default, "", "B" & $row) _Excel_RangeWrite($oBook, Default, "", "C" & $row) _Excel_RangeWrite($oBook, Default, $Formel, "D" & $row) _Excel_RangeWrite($oBook, Default, $Formel, "E" & $row) _Excel_RangeWrite($oBook, Default, $Ergebnis, "F" & $row) $row += 1 Next _Excel_BookSaveAs($oBook, $sExcel) _Excel_Close($oExcel) EndFunc Func _X31_Export($sImportTxt, $sAusgabeX31) ; ── 1. Datei einlesen ──────────────────────────────────── Local $hLese = FileOpen($sImportTxt, 0) If $hLese = -1 Then MsgBox(16, "Fehler", "Importdatei nicht gefunden:" & @CRLF & $sImportTxt) Return SetError(1, 0, False) EndIf Local $aRawLines[10001] $aRawLines[0] = 0 While True Local $sZ = FileReadLine($hLese) If @error = -1 Then ExitLoop $sZ = StringReplace($sZ, Chr(13), "") If $aRawLines[0] < 10000 Then $aRawLines[0] += 1 $aRawLines[$aRawLines[0]] = $sZ EndIf WEnd FileClose($hLese) If $aRawLines[0] = 0 Then MsgBox(16, "Fehler", "Importdatei ist leer.") Return SetError(2, 0, False) EndIf ; ── 2. Kopfdaten lesen ─────────────────────────────────── Local $aKopf[30][2] Local $iKopfN = 0 Local $bInKopf = False For $i = 1 To $aRawLines[0] Local $sL = StringStripWS($aRawLines[$i], 3) If StringInStr($sL, "[Kopfdaten]") Then $bInKopf = True ContinueLoop EndIf If StringLeft($sL, 1) = "[" And $bInKopf Then $bInKopf = False ContinueLoop EndIf If $bInKopf Then Local $iG = StringInStr($sL, "=") If $iG > 0 And $iKopfN < 28 Then $aKopf[$iKopfN][0] = StringStripWS(StringLeft($sL, $iG - 1), 3) $aKopf[$iKopfN][1] = StringStripWS(StringMid($sL, $iG + 1), 3) $iKopfN += 1 EndIf EndIf Next ; Fallback: erste 15 Zeilen If $iKopfN = 0 Then For $i = 1 To ($aRawLines[0] < 15 ? $aRawLines[0] : 15) Local $sF = StringStripWS($aRawLines[$i], 3) Local $pF = StringInStr($sF, "=") If $pF > 0 And $iKopfN < 28 Then $aKopf[$iKopfN][0] = StringStripWS(StringLeft($sF, $pF - 1), 3) $aKopf[$iKopfN][1] = StringStripWS(StringMid($sF, $pF + 1), 3) $iKopfN += 1 EndIf Next EndIf Local $sDatum = _KopfGet($aKopf, "Datum") Local $sBaustelle = _KopfGet($aKopf, "Baustelle") Local $sBauabs = _KopfGet($aKopf, "Bauabschnitt") Local $sVertrag = _KopfGet($aKopf, "Vertrag") Local $sAspaN = _KopfGet($aKopf, "AspaN") Local $sAspaTel = _KopfGet($aKopf, "AspaTel") Local $sAbrufNr = _KopfGet($aKopf, "AbrufNr") Local $sSMNr = _KopfGet($aKopf, "SMNr") Local $sStartZ = _KopfGet($aKopf, "StartZ") Local $sEndZ = _KopfGet($aKopf, "EndZ") Local $sISODatum = _DatumISO($sDatum) Local $sStartISO = _DatumISO($sStartZ) Local $sEndISO = _DatumISO($sEndZ) Local $sUID = _UUID() Local $sBoQUID = _UUID() Local $sLVName = ($sVertrag <> "") ? $sVertrag : ($sBaustelle & " " & $sBauabs) ; Feldlängen auf Dataflor-Limits kürzen ; RefBoQName / RefPrjID: max. 20 Zeichen ; RefPrjName / Name1: max. 50 Zeichen Local $sLVName20 = StringLeft($sLVName, 20) Local $sBaust50 = StringLeft($sBaustelle, 50) ; ── 3. Aufmassdaten parsen ─────────────────────────────── ; Spalten: 1=Ort|2=OZ|3=Faktor|4=Einzelmenge|5|6|7=GesamtMenge| ; 8=Einheit|9=Beschreibung|10=Bemerkung|11=Menge2|12=EP|13=GP Local $aPosData[10001][9] ; [n][0]=OZ [n][1]=Qty(float) [n][2]=Ort [n][3]=Beschreibung ; [n][4]=Bemerkung [n][5]=Einheit [n][6]=EP [n][7]=Faktor [n][8]=EinzelMenge Local $iPosN = 0 Local $bInData = False For $i = 1 To $aRawLines[0] Local $sLine = StringStripWS($aRawLines[$i], 3) If StringInStr($sLine, "[Aufma") Then $bInData = True ContinueLoop EndIf If StringLeft($sLine, 1) = "[" And $bInData Then $bInData = False ContinueLoop EndIf If Not $bInData Then ContinueLoop If $sLine = "" Then ContinueLoop If StringStripWS(StringReplace($sLine, "|", ""), 3) = "" Then ContinueLoop If Not StringInStr($sLine, "|") Then ContinueLoop Local $aS = StringSplit($sLine, "|", $STR_NOCOUNT) Local $nS = UBound($aS) If $nS < 2 Then ContinueLoop Local $sOZ = ($nS > 1) ? StringStripWS($aS[1], 3) : "" If Not _IsValidOZ($sOZ) Then ContinueLoop Local $sOrt = ($nS > 0) ? StringStripWS($aS[0], 3) : "" Local $sFaktor = ($nS > 2) ? StringStripWS($aS[2], 3) : "1" Local $sEinzel = ($nS > 3) ? StringStripWS($aS[3], 3) : "" Local $sGesamt = ($nS > 6) ? StringStripWS($aS[6], 3) : "" Local $sEinh = ($nS > 7) ? StringStripWS($aS[7], 3) : "" Local $sBeschr = ($nS > 8) ? StringStripWS($aS[8], 3) : "" Local $sBemerk = ($nS > 9) ? StringStripWS($aS[9], 3) : "" Local $sEP = ($nS > 11) ? StringStripWS($aS[11], 3) : "" ; Qty berechnen: Faktor * Einzelmenge, oder direkt Gesamtmenge Local $fFaktor = _ToFloat($sFaktor) Local $fEinzel = _ToFloat($sEinzel) Local $fGesamt = _ToFloat($sGesamt) Local $fQty = 0 If $fFaktor <> 1 And $fEinzel <> 0 Then $fQty = $fFaktor * $fEinzel ElseIf $fGesamt <> 0 Then $fQty = $fGesamt ElseIf $fEinzel <> 0 Then $fQty = $fEinzel Else $fQty = $fFaktor EndIf $aPosData[$iPosN][0] = $sOZ $aPosData[$iPosN][1] = $fQty $aPosData[$iPosN][2] = $sOrt $aPosData[$iPosN][3] = $sBeschr $aPosData[$iPosN][4] = $sBemerk $aPosData[$iPosN][5] = $sEinh $aPosData[$iPosN][6] = $sEP $aPosData[$iPosN][7] = $sFaktor $aPosData[$iPosN][8] = $sEinzel $iPosN += 1 If $iPosN >= 10000 Then ExitLoop Next If $iPosN = 0 Then MsgBox(16, "Fehler", "Keine gueltigen Positionen gefunden.") Return SetError(3, 0, False) EndIf ; ── 4. OZ-Schema ermitteln ─────────────────────────────── ; Typ bestimmen und OZ-Typ-spezifische Standard-Lengths setzen ; WICHTIG: Length = Feldbreite laut OZ-Maske, NICHT max. Zeichenlänge des Werts! ; Dataflor liest die Length aus BoQBkdn und ordnet OZ-Segmente zu. ; Falsche Lengths = kein Import (Segmente passen nicht ins Feld). ; ; Standard-Lengths (aus D11-OZ-Masken abgeleitet): ; Typ A (XX.XX.XXXX): L1=2, L2=2, L3=4 (Maske: 22PPPPi) ; Typ B (X.X.XX.XXXX): L1=1, L2=2, L3=3, L4=4 (Maske: 123PPPi) ; Typ C (XXXXXXXX): L1=8 (Maske: PPPPPPPPi) Local $sOZTyp = "A" Local $iMaxPos = 4 For $i = 0 To $iPosN - 1 Local $aOZ = _OZInfo($aPosData[$i][0]) If $aOZ[0] = "B" Then $sOZTyp = "B" If $aOZ[0] = "C" And $sOZTyp = "A" Then $sOZTyp = "C" If $aOZ[9] > $iMaxPos Then $iMaxPos = $aOZ[9] Next ; Feste Standard-Lengths je Typ (aus D11-OZ-Maske) Local $iL1 = 2 ; Typ A/C Standard Local $iL2 = 2 Local $iL3 = 2 Select Case $sOZTyp = "A" $iL1 = 2 ; z.B. '01' $iL2 = 2 ; z.B. '03' ; $iMaxPos bereits 4 für '0008' Case $sOZTyp = "B" $iL1 = 1 ; z.B. '1' (1 Stelle) $iL2 = 2 ; z.B. '3' (Feld 2-stellig laut Maske) $iL3 = 3 ; z.B. '01' (Feld 3-stellig laut Maske '123PPPi') ; $iMaxPos bereits 4 für '0470' Case $sOZTyp = "C" ; keine Ebenen, nur Item EndSelect ; ── 5. OZ-Hierarchie aufbauen ──────────────────────────── Local $aTitel[100] Local $iTitelN = 0 Local $aUTitel[1000][3] ; [n][0]=E1 [n][1]=E2 [n][2]=E3(nur Typ B) Local $iUTitelN = 0 For $i = 0 To $iPosN - 1 Local $aOZI = _OZInfo($aPosData[$i][0]) Local $sE1 = $aOZI[1] Local $sE2 = $aOZI[2] Local $sE3 = $aOZI[3] ; Titel (Ebene 1) If $sE1 <> "" Then Local $bGefT = False For $j = 0 To $iTitelN - 1 If $aTitel[$j] = $sE1 Then $bGefT = True ExitLoop EndIf Next If Not $bGefT Then $aTitel[$iTitelN] = $sE1 $iTitelN += 1 EndIf EndIf ; Untertitel (Ebene 2 + ggf. Ebene 3) If $sE1 <> "" Then Local $bGefU = False For $j = 0 To $iUTitelN - 1 If $aUTitel[$j][0] = $sE1 And $aUTitel[$j][1] = $sE2 And $aUTitel[$j][2] = $sE3 Then $bGefU = True ExitLoop EndIf Next If Not $bGefU Then $aUTitel[$iUTitelN][0] = $sE1 $aUTitel[$iUTitelN][1] = $sE2 $aUTitel[$iUTitelN][2] = $sE3 $iUTitelN += 1 EndIf EndIf Next ; ── 6. Zeit ────────────────────────────────────────────── Local $sTime = StringRight("0" & @HOUR, 2) & ":" & StringRight("0" & @MIN, 2) & ":" & StringRight("0" & @SEC, 2) ; ── 7. XML aufbauen ────────────────────────────────────── Local $sX = "" $sX &= '' & @CRLF $sX &= '' & @CRLF $sX &= '' & @CRLF ; GAEBInfo $sX &= '' $sX &= '3.3' $sX &= '2023-01' $sX &= '' & $sISODatum & '' $sX &= '' $sX &= 'AutoIt REB Engine V1.2' $sX &= 'AutoIt REB X31 Export' $sX &= '' & @CRLF ; QtyDeterm $sX &= '' & @CRLF ; PrjInfo $sX &= '' $sX &= '' & _XE($sBaust50) & '' $sX &= '' & _XE($sLVName20) & '' $sX &= '' & @CRLF ; QtyDetermInfo – NUR MethodDescription laut GAEB DA XML 3.3 Schema! ; PeriodFrom/PeriodTo sind in QtyDetermInfo NICHT erlaubt → Dataflor-Warnung $sX &= '' $sX &= 'REB23003-2009' $sX &= '' & @CRLF ; DP $sX &= '31' & @CRLF ; OWN (leer, aber Pflichtfeld) $sX &= '
' & _XE($sAspaN) & '' $sX &= '' $sX &= '' & _XE($sAspaTel) & '' $sX &= '
' & @CRLF ; CTR (leer, aber Pflichtfeld) $sX &= '
' $sX &= '' $sX &= '
' & @CRLF ; BoQ $sX &= '' & @CRLF $sX &= '' & _XE($sLVName20) & '' $sX &= '' & $sBoQUID & '' & @CRLF ; BoQBkdn – exakt wie funktionierende alte Version ; WICHTIG: No und sind Pflicht für MWM/Dataflor! Select Case $sOZTyp = "A" $sX &= 'BoQLevelTitel' & $iL1 & 'No' $sX &= 'BoQLevelBauteil' & $iL2 & 'No' $sX &= 'ItemPosition' & $iMaxPos & 'No' $sX &= 'IndexIndex1No' Case $sOZTyp = "B" $sX &= 'BoQLevelTitel' & $iL1 & 'No' $sX &= 'BoQLevelBauteil' & $iL2 & 'No' $sX &= 'BoQLevelGewerk' & $iL3 & 'No' $sX &= 'ItemPosition' & $iMaxPos & 'No' $sX &= 'IndexIndex1No' Case $sOZTyp = "C" $sX &= 'BoQLevelTitel2No' $sX &= 'ItemPosition' & $iMaxPos & 'No' $sX &= 'IndexIndex1No' EndSelect $sX &= @CRLF ; Ctlg (Pflichtfeld in alter Version) $sX &= 'idDIN276_1993' $sX &= 'cost group DIN 276-93' $sX &= 'DIN 276-93' & @CRLF ; BoQBody $sX &= '' & @CRLF ; OZ-Zähler für QTakeoff-Blattadressen Local $iOZCnt = 0 ; Typ C: Flachliste unter einer Sammelgruppe If $sOZTyp = "C" Then $sX &= '' & @CRLF $sX &= '' & @CRLF For $i = 0 To $iPosN - 1 Local $aOZC = _OZInfo($aPosData[$i][0]) $sX &= _BuildItem($aOZC[4], $aPosData[$i][1], $aPosData[$i][2], $aPosData[$i][3], $aPosData[$i][4], $iOZCnt, $aPosData[$i][7], $aPosData[$i][8]) Next $sX &= '' & @CRLF $sX &= '' & @CRLF ; Typ A: 2 Ebenen ElseIf $sOZTyp = "A" Then For $t = 0 To $iTitelN - 1 Local $sT = $aTitel[$t] $sX &= '' & @CRLF $sX &= '' & @CRLF For $u = 0 To $iUTitelN - 1 If $aUTitel[$u][0] <> $sT Then ContinueLoop Local $sU = $aUTitel[$u][1] $sX &= '' & @CRLF $sX &= '' & @CRLF For $p = 0 To $iPosN - 1 Local $aOZA = _OZInfo($aPosData[$p][0]) If $aOZA[1] <> $sT Or $aOZA[2] <> $sU Then ContinueLoop $sX &= _BuildItem($aOZA[4], $aPosData[$p][1], $aPosData[$p][2], $aPosData[$p][3], $aPosData[$p][4], $iOZCnt, $aPosData[$p][7], $aPosData[$p][8]) Next $sX &= '' & @CRLF $sX &= '' & @CRLF Next $sX &= '' & @CRLF $sX &= '' & @CRLF Next ; Typ B: 3 Ebenen (E1.E2.E3.Pos) ElseIf $sOZTyp = "B" Then ; Eindeutige E1-Werte (bereits in $aTitel) For $t = 0 To $iTitelN - 1 Local $sTB = $aTitel[$t] $sX &= '' & @CRLF $sX &= '' & @CRLF ; Eindeutige E2-Werte unter diesem E1 Local $aE2List[100] Local $iE2Cnt = 0 For $u = 0 To $iUTitelN - 1 If $aUTitel[$u][0] <> $sTB Then ContinueLoop Local $sE2Chk = $aUTitel[$u][1] Local $bDup = False For $x = 0 To $iE2Cnt - 1 If $aE2List[$x] = $sE2Chk Then $bDup = True ExitLoop EndIf Next If Not $bDup Then $aE2List[$iE2Cnt] = $sE2Chk $iE2Cnt += 1 EndIf Next ; Für jedes E2 unter diesem E1 For $e2i = 0 To $iE2Cnt - 1 Local $sCurE2 = $aE2List[$e2i] $sX &= '' & @CRLF $sX &= '' & @CRLF ; Alle E3-Werte unter diesem E1.E2 For $u = 0 To $iUTitelN - 1 If $aUTitel[$u][0] <> $sTB Then ContinueLoop If $aUTitel[$u][1] <> $sCurE2 Then ContinueLoop Local $sCurE3 = $aUTitel[$u][2] $sX &= '' & @CRLF $sX &= '' & @CRLF ; Positionen unter diesem E1.E2.E3 For $p = 0 To $iPosN - 1 Local $aOZB = _OZInfo($aPosData[$p][0]) If $aOZB[1] <> $sTB Or $aOZB[2] <> $sCurE2 Or $aOZB[3] <> $sCurE3 Then ContinueLoop $sX &= _BuildItem($aOZB[4], $aPosData[$p][1], $aPosData[$p][2], $aPosData[$p][3], $aPosData[$p][4], $iOZCnt, $aPosData[$p][7], $aPosData[$p][8]) Next $sX &= '' & @CRLF $sX &= '' & @CRLF Next $sX &= '' & @CRLF $sX &= '' & @CRLF Next $sX &= '' & @CRLF $sX &= '' & @CRLF Next EndIf $sX &= '' & @CRLF $sX &= '' & @CRLF $sX &= '
' & @CRLF $sX &= '
' ; ── 8. Als echtes UTF-8 mit BOM speichern ──────────────── ; BOM = EF BB BF, dann UTF-8 Bytes ; StringToBinary($s, 4) = UTF-8 Kodierung If FileExists($sAusgabeX31) Then FileDelete($sAusgabeX31) Local $binBOM = Binary("0xEFBBBF") Local $binBody = StringToBinary($sX, 4) Local $binFull = $binBOM & $binBody Local $bOK = FileWrite($sAusgabeX31, $binFull) If Not $bOK Or Not FileExists($sAusgabeX31) Then MsgBox(16, "Fehler", "Ausgabedatei konnte nicht geschrieben werden:" & @CRLF & $sAusgabeX31) Return SetError(4, 0, False) EndIf MsgBox(64, "X31 Export", "X31-Datei erfolgreich erstellt!" & @CRLF & @CRLF & _ "Datei: " & $sAusgabeX31 & @CRLF & _ "Positionen: " & $iPosN & @CRLF & _ "OZ-Typ: " & $sOZTyp & @CRLF & _ "Format: GAEB DA XML 3.3 / DA31 / REB 23.003") Return True EndFunc ; ============================================================================== ; _BuildItem – Einzelnes -Element erzeugen ; Struktur in Dataflor/MWM: ; K-Zeile (*) = RSA-Abschnitt/Ort ; L-Zeile = Formel 91 mit Faktor und Einzelmenge getrennt ; Parameter werden als Einzelwerte übergeben (kein 2D-Array-Slice in AutoIt!) ; ============================================================================== Func _BuildItem($sPosNr, $fQty, $sOrt, $sBeschr, $sBemerk, ByRef $iOZCnt, $sFaktor = "1", $sEinzel = "") ; Qty für XML ( Tag): Punkt als Dezimaltrenner Local $sQtyXML = StringReplace(_FmtQty($fQty), ",", ".") ; Qty für DA11 L-Zeile: Komma, direkt die berechnete Gesamtmenge Local $sQty = _FmtQty($fQty) ; L-Zeilen-Menge = berechnetes Qty (Faktor bereits eingerechnet) ; Exakt wie Dataflor: "100091" + Gesamtmenge + "=" Local $sMenge = $sQty ; Faktor bereinigen Local $sFakClean = StringStripWS($sFaktor, 3) If $sFakClean = "" Or $sFakClean = "0" Then $sFakClean = "1" $sFakClean = StringReplace($sFakClean, ".", ",") ; OZ-Codes für K- und L-Zeile Local $sOZ1 = _REBOZCode($iOZCnt) $iOZCnt += 1 Local $sOZ2 = _REBOZCode($iOZCnt) $iOZCnt += 1 ; K-Zeilen-Text = RSA-Abschnitt (Ort), Fallback auf Bemerkung Local $sKText = $sOrt If $sKText = "" Then $sKText = $sBemerk If $sKText = "" Then $sKText = $sBeschr Local $sItem = "" $sItem &= '' $sItem &= '' $sItem &= '' & $sQtyXML & '' ; K-Zeile: RSA-Abschnitt als Kommentarzeile $sItem &= '' $sItem &= '' $sItem &= '' & _XE(StringStripWS($sBeschr, 3)) & '' $sItem &= '' ; L-Zeile: Formel 91 mit Faktor und Menge getrennt $sItem &= '' $sItem &= '' $sItem &= '' $sItem &= '' $sItem &= '' & @CRLF Return $sItem EndFunc ; ============================================================================== ; Hilfsfunktionen ; ============================================================================== ; K-Zeile: 13sp(*) + Ort(56 Zeichen) + OZCode(6) + 5sp = 80 Zeichen Func _KZeile($sOrt, $sOZCode) Local $sOrtPad = StringLeft($sOrt & " ", 56) Return " *" & $sOrtPad & $sOZCode & " " EndFunc ; L-Zeile: 25sp + "100091" + Menge + "=" + padding auf 44 + BlatAdr(6) + 5sp = 80 Zeichen ; Exakt wie Dataflor-Export: " 100091Menge= BlatAdr " ; Faktor wird als Multiplikator in die Menge eingerechnet (qty = faktor * einzelmenge) ; Der Faktor ist NICHT separat in der Zeile – Dataflor rechnet über die Qty Func _LZeile($sFaktor, $sMenge, $sOZCode) ; Menge mit Komma (DA11-Standard), Punkt entfernen Local $sMengeK = StringReplace(StringStripWS($sMenge, 3), ".", ",") ; Formel: direkt "100091" + Menge + "=" Local $sFormel = "100091" & $sMengeK & "=" ; Auf 44 Zeichen auffüllen While StringLen($sFormel) < 44 $sFormel &= " " WEnd $sFormel = StringLeft($sFormel, 44) Return " " & $sFormel & $sOZCode & " " EndFunc ; REB Blattadresse aus Zähler ; Format: Blattnummer(4) + Zeilenkennung(A-Z) + Index(0) ; idx=0 → "1000A0" ; idx=25 → "1000Z0" ; idx=26 → "1001A0" (nächste Blattnummer) Func _REBOZCode($iIdx) Local $iBlatt = 1000 + Int($iIdx / 26) Local $iZeile = Mod($iIdx, 26) Local $sZeile = Chr(65 + $iZeile) ; 65 = Asc("A") Local $sBlatt = String($iBlatt) Return $sBlatt & $sZeile & "0" EndFunc ; Qty formatieren: ganzzahlig ohne Dezimalstellen, sonst 3 Stellen ; Komma als Dezimaltrenner (DA11-Standard) Func _FmtQty($fVal) Local $fAbs = $fVal If $fAbs < 0 Then $fAbs = -$fAbs Local $iGanz = Int($fAbs + 0.0005) ; gerundet Local $fDez = $fAbs - Int($fAbs) Local $iD3 = Int($fDez * 1000 + 0.5) If $iD3 >= 1000 Then $iGanz += 1 $iD3 = 0 EndIf ; Vorzeichenbehandlung Local $sVorz = "" If $fVal < 0 Then $sVorz = "-" ; Ganzzahlig? → kein Dezimalteil If $iD3 = 0 Then Return $sVorz & String($iGanz) EndIf ; Mit Dezimalstellen: 3 Stellen, Komma Local $sDez = String($iD3) While StringLen($sDez) < 3 $sDez = "0" & $sDez WEnd ; Trailing Zeros entfernen (z.B. 2,500 → 2,5 für saubere Darstellung) While StringRight($sDez, 1) = "0" And StringLen($sDez) > 1 $sDez = StringLeft($sDez, StringLen($sDez) - 1) WEnd Return $sVorz & String(Int($fAbs)) & "," & $sDez EndFunc ; OZ analysieren Func _OZInfo($sOZ) Local $aI[10] $aI[0] = "?" $aI[1] = "" $aI[2] = "" $aI[3] = "" $aI[4] = $sOZ $aI[5] = $sOZ $aI[6] = 0 $aI[7] = 0 $aI[8] = 0 $aI[9] = 0 If $sOZ = "" Then Return $aI If StringRegExp($sOZ, "^\d{6,10}$") Then $aI[0] = "C" $aI[4] = $sOZ $aI[9] = StringLen($sOZ) Return $aI EndIf Local $aS = StringSplit($sOZ, ".", $STR_NOCOUNT) Local $n = UBound($aS) If $n = 3 Then $aI[0] = "A" $aI[1] = $aS[0] $aI[6] = StringLen($aS[0]) $aI[2] = $aS[1] $aI[7] = StringLen($aS[1]) $aI[4] = $aS[2] $aI[9] = StringLen($aS[2]) ElseIf $n = 4 Then $aI[0] = "B" $aI[1] = $aS[0] $aI[6] = StringLen($aS[0]) $aI[2] = $aS[1] $aI[7] = StringLen($aS[1]) $aI[3] = $aS[2] $aI[8] = StringLen($aS[2]) $aI[4] = $aS[3] $aI[9] = StringLen($aS[3]) EndIf $aI[5] = $sOZ Return $aI EndFunc ; OZ-Typ prüfen Func _IsValidOZ($sOZ) If $sOZ = "" Then Return False If StringRegExp($sOZ, "^\d{1,4}\.\d{1,4}\.\d{1,6}$") Then Return True If StringRegExp($sOZ, "^\d{1,4}\.\d{1,4}\.\d{1,4}\.\d{1,6}$") Then Return True If StringRegExp($sOZ, "^\d{6,10}$") Then Return True Return False EndFunc ; Kopfdaten-Wert lesen Func _KopfGet(ByRef $aKopf, $sKey) For $i = 0 To UBound($aKopf) - 1 If $aKopf[$i][0] = $sKey Then Return $aKopf[$i][1] Next Return "" EndFunc ; XML-Sonderzeichen kodieren Func _XE($s) $s = StringReplace($s, "&", "&") $s = StringReplace($s, "<", "<") $s = StringReplace($s, ">", ">") $s = StringReplace($s, '"', """) $s = StringReplace($s, "'", "'") Return $s EndFunc ; String zu Float (Komma→Punkt) Func _ToFloat($s) If $s = "" Then Return 0 Return Number(StringReplace(StringStripWS($s, 3), ",", ".")) EndFunc ; Datum DD.MM.YYYY → YYYY-MM-DD Func _DatumISO($s) $s = StringStripWS($s, 3) If StringRegExp($s, "^\d{2}\.\d{2}\.\d{4}$") Then Local $aD = StringSplit($s, ".", $STR_NOCOUNT) Return $aD[2] & "-" & $aD[1] & "-" & $aD[0] EndIf Return $s EndFunc ; Fortlaufende DF_-ID Func _NextID() $g_iIDCnt += 1 Return $g_iIDCnt EndFunc ; Pseudo-UUID Func _UUID() Local $sHex = "0123456789abcdef" Local $sUID = "" Local $aLen[5] $aLen[0] = 8 $aLen[1] = 4 $aLen[2] = 4 $aLen[3] = 4 $aLen[4] = 12 For $i = 0 To 4 If $i > 0 Then $sUID &= "-" For $j = 1 To $aLen[$i] $sUID &= StringMid($sHex, Random(1, 16, 1), 1) Next Next Return $sUID EndFunc