How to generate letters in Word with custom fields

elwin68elwin68 Member Posts: 153
Hello,

For a client custom tables are made in NAV2009 SP1 (classic client).
Now a solution must be made to create letters in Word including custom fields.
The client must be able to generate the templates in Word himself. It would be nice letters can be generated and printed through a batch.

The following options are possible:
- Interaction template
Custom fields can't be used.
It can be programmed to use custom fields but only a maximum number of fields can be used.
- Style sheets
It can not be called through code behind a button.
It can not be used through a batch.

Does anyone have a flexibel solution?

Thanks in advance.

Answers

  • Remco_ReinkingRemco_Reinking Member Posts: 74
    Add a function to call the stylesheet functionality through code.
    See attachment for this function (add it in codeunit 403)

    It can be called like this:

    //gAppLaunchMgt Codeunit Application Launch Management
    //gPKRecRef RecordRef

    gPKRecRef.GETTABLE( BaseRecordInStyleSheet);
    gAppLaunchMgt.LaunchAppManual( gPKRecRef,
    StyleSheetToUse, // somewhere the user has chosen this one, or set in setup record
    ExportFormat::PDF, // or " ", DOC, HTML, TXT
    PathToStoreFile,
    {VAR} FileNameCreated);

    This works in a 5.0SP1 environment on SQL with 3.70 functionality

    Function looks like this:
    PROCEDURE LaunchAppManual@1000000000(PKRecRef@1000000000 : RecordRef;StylesheetTemplateCode@1000000010 : Code[20];SaveAs@1000000017 : 'None,DOCX,PDF,HTML,TXT';PathName@1000000023 : Text[250];VAR vTxtFileName@1000000021 : Text[250]) : Boolean;
    VAR
      DataXML@1000000008 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 4.0:{88D969C0-F192-11D4-A65F-0040963251E5}:'Microsoft XML, v4.0'.DOMDocument40";
      ApplicationXML@1000000006 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 4.0:{88D969C0-F192-11D4-A65F-0040963251E5}:'Microsoft XML, v4.0'.DOMDocument40";
      DataXMLNode@1000000003 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 4.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v4.0'.IXMLDOMNode";
      WordApp@1000000002 : Automation "{00020905-0000-0000-C000-000000000046} 8.4:{000209FF-0000-0000-C000-000000000046}:'Microsoft Word 12.0 Object Library'.Application";
      WordAppDoc@1000000001 : Automation "{00020905-0000-0000-C000-000000000046} 8.4:{0002096C-0000-0000-C000-000000000046}:'Microsoft Word 12.0 Object Library'.Documents";
      StyleSheetLink@1000000014 : Record 685;
      PKKeyRef@1000000004 : KeyRef;
      PKCurKeyRef@1000000016 : KeyRef;
      PKFieldRef@1000000007 : FieldRef;
      TextWordNotFound@1000000011 : TextConst 'ENU=Word not found.;NLD=MS-Word niet gevonden.';
      UrlStr@1000000009 : ARRAY [2] OF Text[1024];
      FileName@1000000015 : Text[1024];
      FileNameDoc@1000000018 : Text[1024];
      FieldCount@1000000005 : Integer;
      wdExportFormatPDF@1000000012 : Integer;
      wdFormatText@1000000013 : Integer;
      wdFormatHTML@1000000020 : Integer;
      wdFormatXMLDocument@1000000022 : Integer;
      OpenAfterExport@1000000019 : Boolean;
    BEGIN
      //STYLESHEET-01.ns
      CREATE(ApplicationXML);
      CREATE(DataXML);
    
      PKCurKeyRef := PKRecRef.KEYINDEX(PKRecRef.CURRENTKEYINDEX);
      FOR FieldCount := 1 TO PKCurKeyRef.FIELDCOUNT DO BEGIN
        PKFieldRef := PKCurKeyRef.FIELDINDEX(FieldCount);
        UrlStr[1] += 'Field' + FORMAT(PKFieldRef.NUMBER);
        IF FieldCount < PKCurKeyRef.FIELDCOUNT THEN UrlStr[1] += ','
      END;
      UrlStr[1] := '%26view=SORTING(' + UrlStr[1] + ')';
    
      PKKeyRef := PKRecRef.KEYINDEX(1);
      FOR FieldCount := 1 TO PKKeyRef.FIELDCOUNT DO BEGIN
        PKFieldRef := PKKeyRef.FIELDINDEX(FieldCount);
        UrlStr[2] += 'Field' + FORMAT(PKFieldRef.NUMBER) + '=0(' + FORMAT(PKFieldRef.VALUE) + ')';
        IF FieldCount < PKCurKeyRef.FIELDCOUNT THEN UrlStr[2] += ',';
        IF FieldCount > 1 THEN FileName += ' ';
        FileName += FORMAT(PKFieldRef.VALUE);
      END;
      UrlStr[2] := '%26position=' + UrlStr[2] + '%26servertype=MSSQL';
    
      IF PathName<>'' THEN
      BEGIN
        IF PathName[STRLEN( PathName)] <> '\' THEN
          PathName += '\';
        FileName := PathName+FileName;
      END;
    
      DataXMLNode := DataXML.createNode(1, 'Object', '');
      DataXML.appendChild(DataXMLNode);
      AddAttribute(DataXMLNode, 'url', UrlStr[1] + UrlStr[2]);
    
      StyleSheetLink.SETFILTER("Template Code",StylesheetTemplateCode);
      StyleSheetLink.FINDSET;
    
      LaunchApp(DataXML,StyleSheetLink."Style Sheet ID",ApplicationXML);
    
      IF NOT CREATE(WordApp,TRUE) THEN
        ERROR(TextWordNotFound);
    
      FileNameDoc := FileName + '.doc';             // TEMP
      IF EXISTS(FileNameDoc) THEN ERASE(FileNameDoc);
      ApplicationXML.save(FileNameDoc);
    
      WordApp.Visible := FALSE;
    
      WordApp.Documents.Open(FileNameDoc);
    
      CASE SaveAs OF
        SaveAs::PDF:
        BEGIN
          FileNameDoc := FileName + '.pdf';
          IF EXISTS(FileNameDoc) THEN ERASE(FileNameDoc);
          wdExportFormatPDF := 17;
          OpenAfterExport := FALSE;
          WordApp.ActiveDocument.ExportAsFixedFormat( FileNameDoc,wdExportFormatPDF,OpenAfterExport);
        END;
        SaveAs::TXT:
        BEGIN
          FileNameDoc := FileName + '.txt';             // TEMP
          IF EXISTS(FileNameDoc) THEN ERASE(FileNameDoc);
          wdFormatText := 2;
          WordApp.ActiveDocument.SaveAs( FileNameDoc, wdFormatText);
        END;
        SaveAs::HTML:
        BEGIN
          FileNameDoc := FileName + '.html';
          IF EXISTS(FileNameDoc) THEN ERASE(FileNameDoc);
          wdFormatHTML := 10;//    wdFormatFilteredHTML = 10
          WordApp.ActiveDocument.SaveAs( FileNameDoc, wdFormatHTML);
        END;
        SaveAs::DOCX:
        BEGIN
          FileNameDoc := FileName + '.docx';
          IF EXISTS(FileNameDoc) THEN ERASE(FileNameDoc);
          wdFormatXMLDocument := 12;
          WordApp.ActiveDocument.SaveAs( FileNameDoc, wdFormatXMLDocument);
        END;
      ELSE
        WordApp.Visible(TRUE);
      END;
    
      vTxtFileName := FileNameDoc;
    
      WordApp.Documents.Close;
      WordApp.Quit;
      //STYLESHEET-01.ne
    END;
    
    
  • elwin68elwin68 Member Posts: 153
    Thanks for your solution.
    I will look if it is possible in NAV2009SP1.
  • vaprogvaprog Member Posts: 1,146
    How does it work?
    Who's going to process the url attribute you create? There's no code to do this in my version.

    Checked NAVW16.00.01 (2009 SP1 R2) and NAVW15.00 (NAV 5.0 SP1).
  • SogSog Member Posts: 1,023
    I dno, maybe Word might do the trick. It is a word template.
    |Pressing F1 is so much faster than opening your browser|
    |To-Increase|
  • mdPartnerNLmdPartnerNL Member Posts: 802
    vaprog wrote:
    How does it work?
    Who's going to process the url attribute you create? There's no code to do this in my version.

    Checked NAVW16.00.01 (2009 SP1 R2) and NAVW15.00 (NAV 5.0 SP1).

    Yes, you are correct. It creates a node in an empty XML Document. Maybe Remco isn't working with NAV anymore for this :)
  • mdPartnerNLmdPartnerNL Member Posts: 802
    Ok, I have updated it a bit to make it work. Thank you Remco for the example :)

    1.
    To test and start it.
        PROCEDURE RxTestLaunchAppManual@1000000014();
        VAR
          LrCustomer@1000000000 : Record 18;
          LrrefRecord@1000000001 : RecordRef;
          LoptSaveAs@1000000002 : 'None,DOCX,PDF,HTML,TXT';
          LtFilePathName@1000000003 : Text[250];
        BEGIN
          LtFilePathName := '';
          LrCustomer.RESET;
          LrCustomer.FINDFIRST;
          LrrefRecord.GETTABLE(LrCustomer);
          RxLaunchAppManual(LrrefRecord, 'Klantkaart voor brief Microsoft Word', LoptSaveAs::DOCX, 'd:\', LtFilePathName, FALSE, 21);
        END;
    

    2.
    The new code.
        PROCEDURE RxLaunchAppManual@11083986(PrrefRecord@1000000000 : RecordRef;PtStylesheetTemplate@1000000010 : Text[250];PoptSaveAs@1000000017 : 'None,DOCX,PDF,HTML,TXT';PtFilePath@1000000023 : Text[250];VAR vPtFilePathName@1000000021 : Text[250];PbCloseApplication@1000000022 : Boolean;PiFormID@1000000011 : Integer) : Boolean;
        VAR
          LaXMLDocument@1000000008 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{88D96A05-F192-11D4-A65F-0040963251E5}:'Microsoft XML, v6.0'.DOMDocument60";
          LaXMLDocumentApplication@1000000006 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{88D96A05-F192-11D4-A65F-0040963251E5}:'Microsoft XML, v6.0'.DOMDocument60";
          LaXMLNode@1000000003 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v6.0'.IXMLDOMNode";
          LaXMLNodeControl1@1000000027 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v6.0'.IXMLDOMNode";
          LaXMLNodeControl2@1000000028 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v6.0'.IXMLDOMNode";
          LaXMLNodeRow@1000000029 : Automation "{F5078F18-C551-11D3-89B9-0000F81FE221} 6.0:{2933BF80-7B36-11D2-B20E-00C04F983E60}:'Microsoft XML, v6.0'.IXMLDOMNode";
          LaWdApp@1000000002 : Automation "{00020905-0000-0000-C000-000000000046} 8.4:{000209FF-0000-0000-C000-000000000046}:Unknown Automation Server.Application";
          LaWdDocument@1000000001 : Automation "{00020905-0000-0000-C000-000000000046} 8.4:{0002096C-0000-0000-C000-000000000046}:Unknown Automation Server.Documents";
          LkrefPrimKey@1000000004 : KeyRef;
          LkrefCurrentKey@1000000016 : KeyRef;
          LfrefField@1000000007 : FieldRef;
          UrlStr@1000000009 : ARRAY [2] OF Text[1024];
          LtFilePathName@1000000015 : Text[512];
          LtFilePathNameDoc@1000000018 : Text[512];
          LiFieldCount@1000000005 : Integer;
          LrStyleSheet@1000000014 : Record 2000000066;
          LguidRxLastProgram@1000000024 : GUID;
          LiConstwdExportFormatPDF@1000000020 : Integer;
          LiConstwdFormatText@1000000019 : Integer;
          LiConstwdFormatHTML@1000000013 : Integer;
          LiConstwdFormatXMLDocument@1000000012 : Integer;
          LbConstOpenAfterExport@1000000025 : Boolean;
          GtcNoWord@1000000026 : TextConst 'ENU=MsWord not found.;NLD=MsWord niet gevonden.';
        BEGIN
          //MOD_RX
          //http://www.mibuso.com/forum/viewtopic.php?f=23&t=43516&sid=5d6db25f72ba4922227b8dce658e4ca4
    
          LkrefCurrentKey := PrrefRecord.KEYINDEX(PrrefRecord.CURRENTKEYINDEX);
          FOR LiFieldCount := 1 TO LkrefCurrentKey.FIELDCOUNT DO BEGIN
            LfrefField := LkrefCurrentKey.FIELDINDEX(LiFieldCount);
            UrlStr[1] += 'Field' + FORMAT(LfrefField.NUMBER);
            IF LiFieldCount < LkrefCurrentKey.FIELDCOUNT THEN UrlStr[1] += ','
          END;
          UrlStr[1] := '%26view=SORTING(' + UrlStr[1] + ')';
    
          LkrefPrimKey := PrrefRecord.KEYINDEX(1);
          FOR LiFieldCount := 1 TO LkrefPrimKey.FIELDCOUNT DO BEGIN
            LfrefField := LkrefPrimKey.FIELDINDEX(LiFieldCount);
            UrlStr[2] += 'Field' + FORMAT(LfrefField.NUMBER) + '=0(' + FORMAT(LfrefField.VALUE) + ')';
            IF LiFieldCount < LkrefCurrentKey.FIELDCOUNT THEN UrlStr[2] += ',';
            IF LiFieldCount > 1 THEN LtFilePathName += ' ';
            LtFilePathName += FORMAT(LfrefField.VALUE);
          END;
          UrlStr[2] := '%26position=' + UrlStr[2] + '%26servertype=MSSQL';
    
          IF PtFilePath<>'' THEN
          BEGIN
            IF PtFilePath[STRLEN( PtFilePath)] <> '\' THEN BEGIN
              PtFilePath += '\';
            END;
            LtFilePathName := PtFilePath+LtFilePathName;
          END;
    
          CREATE(LaXMLDocumentApplication);
          CREATE(LaXMLDocument);
    
          LaXMLDocument.async := FALSE;
          LaXMLDocument.loadXML(
            '<?xml version="1.0" encoding="UTF-8" standalone="no"?><Object>' + '</Object>');
          LaXMLNode := LaXMLDocument.documentElement;
          AddAttribute(LaXMLNode, 'url', UrlStr[1] + UrlStr[2]);
          AddAttribute(LaXMLNode, 'type', 'Form');
          AddAttribute(LaXMLNode, 'id', FORMAT(PiFormID));
    
          AddElement(LaXMLNode,'Control','',LaXMLNodeControl1);
          AddAttribute(LaXMLNodeControl1,'type','TabControl');
    
          AddElement(LaXMLNodeControl1,'Control','',LaXMLNodeControl2);
          AddAttribute(LaXMLNodeControl2,'type','TabPage');
    
          AddElement(LaXMLNodeControl2,'Row','',LaXMLNodeRow);
          AddElement(LaXMLNodeRow,'Control','',LaXMLNodeControl1);
          AddAttribute(LaXMLNodeControl1,'type','Label');
          AddElement(LaXMLNodeRow,'Control','',LaXMLNodeControl2);
          AddAttribute(LaXMLNodeControl2,'type','TextBox');
          AddAttribute(LaXMLNodeControl2,'value','30000');
    
          //LaXMLDocument.save('d:\manualobject.xml');
    
          LrStyleSheet.RESET;
          LrStyleSheet.SETFILTER(Name,PtStylesheetTemplate);
          IF (NOT LrStyleSheet.FINDFIRST) THEN BEGIN
            EXIT;
          END;
    
          CLEAR(LguidRxLastProgram); //No ReportX
          LaunchApp(LaXMLDocument,LrStyleSheet."Style Sheet ID",LaXMLDocumentApplication, LguidRxLastProgram);
    
          IF NOT CREATE(LaWdApp,FALSE, TRUE) THEN BEGIN
            ERROR(GtcNoWord);
          END;
    
          LtFilePathNameDoc := LtFilePathName + '.doc'; // TEMP
          IF EXISTS(LtFilePathNameDoc) THEN ERASE(LtFilePathNameDoc);
          LaXMLDocumentApplication.save(LtFilePathNameDoc);
    
          LaWdApp.Visible := TRUE;
          LaWdApp.Documents.Open(LtFilePathNameDoc);
    
          CASE PoptSaveAs OF
            PoptSaveAs::PDF:
            BEGIN
              LtFilePathNameDoc := LtFilePathName + '.pdf';
              IF EXISTS(LtFilePathNameDoc) THEN ERASE(LtFilePathNameDoc);
              LiConstwdExportFormatPDF := 17;
              LbConstOpenAfterExport := FALSE;
              LaWdApp.ActiveDocument.ExportAsFixedFormat(LtFilePathNameDoc,LiConstwdExportFormatPDF,LbConstOpenAfterExport);
            END;
            PoptSaveAs::TXT:
            BEGIN
              LtFilePathNameDoc := LtFilePathName + '.txt'; // TEMP
              IF EXISTS(LtFilePathNameDoc) THEN ERASE(LtFilePathNameDoc);
              LiConstwdFormatText := 2;
              LaWdApp.ActiveDocument.SaveAs(LtFilePathNameDoc, LiConstwdFormatText);
            END;
            PoptSaveAs::HTML:
            BEGIN
              LtFilePathNameDoc := LtFilePathName + '.html';
              IF EXISTS(LtFilePathNameDoc) THEN ERASE(LtFilePathNameDoc);
              LiConstwdFormatHTML := 10;//    LiConstwdFormatFilteredHTML = 10
              LaWdApp.ActiveDocument.SaveAs(LtFilePathNameDoc, LiConstwdFormatHTML);
            END;
            PoptSaveAs::DOCX:
            BEGIN
              LtFilePathNameDoc := LtFilePathName + '.docx';
              IF EXISTS(LtFilePathNameDoc) THEN ERASE(LtFilePathNameDoc);
              LiConstwdFormatXMLDocument := 12;
              LaWdApp.ActiveDocument.SaveAs(LtFilePathNameDoc, LiConstwdFormatXMLDocument);
            END;
          ELSE
            LaWdApp.Visible(TRUE);
          END;
    
          vPtFilePathName := LtFilePathNameDoc;
    
          LaWdApp.Documents.Close;
          IF (PbCloseApplication) THEN BEGIN
            LaWdApp.Quit;
          END;
    
          CLEAR(LaXMLDocumentApplication);
          CLEAR(LaXMLDocument);
        END;
    

    3.
    I have made MS-Word visible.
  • rocatisrocatis Member Posts: 163
    Forgive me for being lazy, but I've just realized that the posted code does not compile under NAV2009 because the AddElement function has been changed.

    Has anybody fixed this?
    Brian Rocatis
    Senior NAV Developer
    Elbek & Vejrup
Sign In or Register to comment.