25. April 2024 08:54
25. April 2024 09:07
25. April 2024 09:12
25. April 2024 09:25
25. April 2024 09:30
25. April 2024 11:18
Kowa hat geschrieben:Eventuell reicht denen ja auch ein technisches Update
26. April 2024 08:54
Timo Lässer hat geschrieben:Es ist also keine Frage nach der technischen Machbarkeit [...]
 (siehe SEPA-Verarbeitung OPplus in den alten Versionen, die boten wir seinerzeit auch ab NAV 2.6 an als "SEPA Sorglos"
 (siehe SEPA-Verarbeitung OPplus in den alten Versionen, die boten wir seinerzeit auch ab NAV 2.6 an als "SEPA Sorglos"  )
 )
			
		26. April 2024 10:35
12. September 2024 19:37
Kowa hat geschrieben:XML-Dateien kann man auch schon unter DOS mit Navision "blau" erzeugen und verarbeiten, das geht mit reinem C/AL wunderbar
 
 13. September 2024 08:00
13. September 2024 09:21
MF hat geschrieben:Geht das auch mit NAV2.01?
13. September 2024 09:29
13. September 2024 10:28
Besser wäre aber aus meiner Sicht, eine XML direkt aus NAV zu erstellen. Die könnte ich dann einfach mit PDFmailer an die E-Mail mit der PDF-Rechnung anhängen.
13. September 2024 10:57
MF hat geschrieben:Geht das über OCX, Automation?
13. September 2024 13:12
13. September 2024 13:19
 . Nachtrag: Lesefunktionen hier.
 . Nachtrag: Lesefunktionen hier.   CRLF[1] := 13;
   CRLF[2] := 10;    PROCEDURE cont@1234522(Stream@1234504 : OutStream;Tag@1234502 : Text[30];Text@1234503 : Text[1024]);
    BEGIN
      IF Indent THEN
        Stream.WRITETEXT(PADSTR('',2*(IX+1)));
      Stream.WRITETEXT('<' + Tag + '>' + Text + '</' + Tag + '>');
      Stream.WRITETEXT(CRLF);
    END;
    PROCEDURE contAttrib@1234521(Stream@1234506 : OutStream;Tag@1234502 : Text[30];Text@1234503 : Text[1024];AttribTag@1234504 : Text[30];AttribValue@1234505 : Text[30]);
    BEGIN
      IF Indent THEN
        Stream.WRITETEXT(PADSTR('',2*(IX+1)));
      Stream.WRITETEXT('<' + Tag + ' ' + AttribTag + '="' + AttribValue +'">' + Text + '</' + Tag + '>');
      Stream.WRITETEXT(CRLF);
    END;
    PROCEDURE push@1234519(Stream@1234503 : OutStream;Tag@1234502 : Text[30]);
    BEGIN
      IX += 1;
      Stack[IX] := Tag;
      IF Indent THEN
        Stream.WRITETEXT(PADSTR('',2*IX));
      Stream.WRITETEXT('<' + Tag + '>');
      Stream.WRITETEXT(CRLF);
    END;
    PROCEDURE pop@1234518(Stream@1234502 : OutStream);
    BEGIN
      IF Indent THEN
        Stream.WRITETEXT(PADSTR('',2*IX));
      Stream.WRITETEXT('</' + Stack[IX] + '>') ;
      IX -= 1;
      Stream.WRITETEXT(CRLF);
    END;      XS.WRITETEXT('<?xml version="1.0" encoding="UTF-8"?>' + CRLF);
      IF Location <> '' THEN
        XS.WRITETEXT(
          '<Document xmlns=' + XMLNS +
          ' xmlns:xsi=' + XSI +
          ' xsi:schemaLocation=' + Location + '>')
      ELSE
        XS.WRITETEXT(
          '<Document xmlns=' + XMLNS +
          ' xmlns:xsi=' + XSI + '>');
      XS.WRITETEXT(CRLF);
      IF painVersion > 2 THEN
        push(XS,'CstmrCdtTrfInitn')
      ELSE
        push(XS,'pain.001.001.02');
      // Header
      push(XS,'GrpHdr');
        cont(XS,'MsgId',COPYSTR(PmtType + '/' + Tools.SEPA_String(PmtHead."Gen. Journal Batch"),1,SEPA_SHORTSTRING));
        cont(XS,'CreDtTm',MakeISODateTime(TODAY));
        cont(XS,'NbOfTxs',FORMAT(TransactionCounter));
        IF painVersion < 3 THEN BEGIN
          cont(XS,'CtrlSum',CONVERTSTR(FORMAT(TotalAmount,0,'<Integer><Decimals,3>'),',','.'));
          IF SepaOld THEN
            cont(XS,'Grpg','GRPD')
          ELSE IF OPplusPmtSetup.SepaGrouping > 0 THEN
            cont(XS,'Grpg',FORMAT(OPplusPmtSetup.SepaGrouping))
          ELSE
            cont(XS,'Grpg','MIXD');
        END;
        push(XS,'InitgPty');
          IF (painVersion = 2) AND (BankCountryCode = 'AT') THEN BEGIN // END ELSE BEGIN
            push(XS,'Id');
              push(XS,'OrgId');
                cont(XS,'BkPtyId',OtherOrdererID);
              pop(XS);
            pop(XS);
          END ELSE BEGIN
            cont(XS,'Nm',SenderName);
            IF SepaOld THEN
              SepaPstlAdr(XS,TRUE,CompanyInfo,FALSE); // kein erw. Zn.Satz vor Version 3
          END;
        pop(XS);
      pop(XS);  // </GrpHdr>            push(XS,'Amt');
              contAttrib(XS,'InstdAmt', CONVERTSTR(FORMAT(Amount,0,'<Integer><Decimals,3>'),',','.'), 'Ccy','EUR');
            pop(XS);13. September 2024 13:45
13. September 2024 14:04
Kowa hat geschrieben:Die erzeugte Datei nach UTF-8 konvertieren kann man z.B. mit PowerShell wie hier: viewtopic.php?f=17&t=25726&#p138532
13. September 2024 14:55
 
 15. September 2024 00:38
    PROCEDURE xttSegmentCopy@1234528(VAR offSet@1234502 : Integer;document@1234503 : BigText;tag@1234504 : Text[30];VAR segment@1234505 : BigText);
    VAR
      maxInt@1234507 : Integer;
      myPos@1234506 : Integer;
      needle@1234508 : Text[30];
    BEGIN
      // komplettes Segment <tag> ... </tag> ab Position "offSet" aus einem Text(fragment) kopieren
      // und den Zeiger aktualisieren
      maxInt := document.LENGTH;
      document.GETSUBTEXT(document,offSet,maxInt);
      myPos := document.TEXTPOS('<' + tag + '>');
      IF myPos > 0 THEN BEGIN
        offSet += myPos;
        document.GETSUBTEXT(segment,myPos,maxInt);
        needle := '</' + tag + '>';
        myPos := segment.TEXTPOS(needle);
        IF myPos > 0 THEN BEGIN
          segment.GETSUBTEXT(segment,1,myPos+STRLEN(needle)-1);
          offSet += myPos;
        END ELSE BEGIN // eigentlich Error
          CLEAR(segment);
          offSet := 0;
        END;
      END ELSE BEGIN
        CLEAR(segment);
        offSet := 0;
      END;
    END;
    PROCEDURE xttSegmentCut@1234532(VAR document@1234503 : BigText;tag@1234504 : Text[30];VAR segment@1234505 : BigText);
    VAR
      maxInt@1234507 : BigInteger;
      myPos@1234506 : Integer;
      myPos2@1234502 : Integer;
      needle@1234508 : Text[30];
      part1@1234510 : BigText;
      part2@1234509 : BigText;
    BEGIN
      // komplettes Segment <tag> ... </tag> aus einem Text(fragment) ausschneiden
      // aus einem Text(fragment) ausschneiden
      needle := '<' + tag + '>';
      myPos := document.TEXTPOS(needle);
      needle := '</' + tag + '>';
      myPos2 := document.TEXTPOS(needle);
      IF (myPos > 0) AND (myPos2 > 0) THEN BEGIN
        myPos2 += STRLEN(needle);
        document.GETSUBTEXT(segment,myPos,myPos2-myPos);
        document.GETSUBTEXT(part1,1,myPos-1);
        document.GETSUBTEXT(part2,myPos2,maxInt);
        CLEAR(document);
        document.ADDTEXT(part1);
        document.ADDTEXT(part2);
      END ELSE
        CLEAR(segment);
    END;
    PROCEDURE xttFirstField@1234537(Haystack@1234502 : BigText;Fieldname@1234503 : Text[30]) result : Text[1024];
    VAR
      maxInt@1234506 : BigInteger;
      needle@1234504 : Text[30];
      myPos@1234505 : Integer;
    BEGIN
      // Den Text des ersten <Fieldname></Fieldname> in Haystack extrahieren:
      // ohne Attribute; "Haystack" kann ein beliebiges Fragment sein.
      needle := '<' + Fieldname + '>';
      myPos := Haystack.TEXTPOS(needle);
      IF myPos > 0 THEN BEGIN
        maxInt := Haystack.LENGTH;
        Haystack.GETSUBTEXT(Haystack,myPos+STRLEN(needle),maxInt);
        needle := '</' + Fieldname + '>';
        myPos := Haystack.TEXTPOS(needle);
        IF myPos > 0 THEN BEGIN
          Haystack.GETSUBTEXT(result,1,myPos-1);
          result := DELCHR(result,'<>',' ');
        END ELSE
          result := ''; // eigentlich Error
      END ELSE
        result := '';
    END;
    PROCEDURE xttFirstFieldAttr@1234530(Haystack@1234505 : BigText;FieldName@1234506 : Text[30];VAR Attrib@1234507 : Text[30]) result : Text[1024];
    VAR
      maxInt@1234502 : Integer;
      myPos@1234503 : Integer;
      needle@1234504 : Text[30];
    BEGIN
      // Den Text des ersten <Fieldname></Fieldname> in Haystack extrahieren:
      // ggf. mit dem _ersten_ Attribut; "Haystack" kann ein beliebiges Fragment sein.
      needle := '</' + FieldName + '>';
      myPos := Haystack.TEXTPOS(needle);
      IF myPos > 0 THEN BEGIN
        Haystack.GETSUBTEXT(Haystack,1,myPos-1);
        needle := '<' + FieldName;
        myPos := Haystack.TEXTPOS(needle);
        IF myPos > 0 THEN BEGIN
          maxInt := Haystack.LENGTH;
          Haystack.GETSUBTEXT(result,myPos,maxInt);
          IF AttribSeparator = '' THEN
            IF STRPOS(result,'"') <> 0 THEN
              AttribSeparator := '"'
            ELSE IF STRPOS(result,'''') <> 0 THEN
              AttribSeparator := ''''
            ELSE AttribSeparator := '"';
          Attrib := COPYSTR(result, STRPOS(result,AttribSeparator) + 1, maxInt);
          Attrib := COPYSTR(Attrib, 1, STRPOS(Attrib,AttribSeparator) -1);
          result := COPYSTR(result, STRPOS(result,'>') + 1, maxInt);
          result := DELCHR(result,'<>',' ');
        END ELSE
          result := ''; // eigentlich Error
      END ELSE
        result := '';
    END;
    PROCEDURE xttSubFieldXP@1234531(Haystack@1234502 : BigText;xPath@1234503 : Text[255]) result : Text[1024];
    VAR
      maxInt@1234504 : Integer;
      myPos@1234505 : Integer;
      myPos2@1234507 : Integer;
      needle@1234506 : Text[30];
    BEGIN
      // ein Feld per Pfad aus einem Abschnitt extrahieren
      // Pfad durchlaufen
      maxInt := Haystack.LENGTH;
      REPEAT
        myPos := STRPOS(xPath,'/');
        IF myPos > 0 THEN BEGIN
          needle := '<' + COPYSTR(xPath,1,myPos-1) + '>';
          xPath := COPYSTR(xPath,myPos+1,MAXSTRLEN(xPath));
        END ELSE
          needle := '<' + xPath + '>';
        myPos2 := Haystack.TEXTPOS(needle);
        IF myPos2 > 0 THEN BEGIN
          Haystack.GETSUBTEXT(Haystack,myPos2 + STRLEN(needle),maxInt);
        END ELSE EXIT(result);
      UNTIL myPos < 1;
      // Feld holen, wenn nicht leer
      needle := '</' + xPath + '>';
      myPos := Haystack.TEXTPOS(needle);
      IF myPos > 0 THEN BEGIN
        Haystack.GETSUBTEXT(result,1,myPos-1);
        result := DELCHR(result,'<>',' '+ TAB + CRLF);
      END ELSE
        result := '';
    END;
          IF StatementNo = '' THEN
            StatementNo := xttFirstField(Segment,'LglSeqNb');
          IF StatementNo = '' THEN
            StatementNo := xttFirstField(Segment,'ElctrncSeqNb');     
     PortCodeOption::"CAMT.054":
            BEGIN
              PosEntry := 1;
              xttSegmentCopy(PosEntry,EntryDtl,'TxAmt',segment);
              field := xttFirstFieldAttr(segment,'Amt',Attrib);
              pathNtry := '';
            END
        // SDD betreffende Felder
        path := pathNtry + 'TxDtls/Refs/';
        field := xttSubFieldXP(EntryDtl, path + 'PmtInfId');
        IF field <> '' THEN
          "Reason Row 10" := COPYSTR('PmtInfId: ' + field,1,MAXSTRLEN("Reason Row 10"));
        field := xttSubFieldXP(EntryDtl, path + 'EndToEndId');
   
        // Verwendungszweck (unstrukturiert)
        offset := 1;
        counter := 0;
        xttSegmentCopy(offset,EntryDtl,'Ustrd',segment);
        WHILE offset > 0 DO BEGIN
          counter += 1;
          ProcessUstrd(segment,counter);
          xttSegmentCopy(offset,EntryDtl,'Ustrd',segment);
        END;
19. September 2024 12:06
19. September 2024 12:30
19. September 2024 13:06
fiddi hat geschrieben:Deshalb meine Frage:
Welches Format bekommst du tatsächlich aus NAV heraus?
XRechnung kannst du mit Bordmitteln erstellen, sofern deine NAV- Version XML kann (eine PDF muss da nicht drin sein).
Für die Factur-X- Rechnung benötigst du ein externes Tool und eine andere XML-Datei, um aus einer PDF-Rechnung (würde je nach Version aus NAV gehen) und deinem XML-Teil eine PDF-A/3- Datei zu machen. Das könntest du, wie in deinem Link beschrieben mit GhostScript machen.
Arbeitest du mit BC als SaaS, wird Microsoft zumindest am Anfang nur die XRechnung unterstützen, weil BC (noch) kein PDF-A/3 kann.
Gruß Fiddi
19. September 2024 15:13
 
 19. September 2024 15:14