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 [...]
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
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