Dynamics CRM 365: загрузка шаблона Word-документа с помощью кнопки на ленте

В настоящее время пользователи должны нажимать на эллипсы, шаблоны слов и, наконец, цитировать, чтобы загрузить шаблон слов.

эллипсы, шаблоны слов и, наконец, цитата

Чтобы было проще для наших пользователей, мы бы хотели, чтобы документ загружался при нажатии кнопки "печатать цитаты" на ленте.

распечатать цитату

Это возможно? Если так, то как мне поступить? Я понимаю, как редактировать ленту, используя ленточный верстак. Мне нужно знать, как загрузить шаблон слова, используя ленту. ленточный верстак

Если в решении используется ленточное рабочее место, какую команду можно ввести, чтобы получить шаблон слова для загрузки?

7 ответов

Решение

ExecuteWordMerge = function (wordtemplateid, entitytypecodeint, ids, templatetype, fieldforfilename, filenameoverride) {
        try {
            Xrm.Page.ui.clearFormNotification("worderror");
            var funcpath = Xrm.Page.context.getClientUrl() + "/_grid/print/print_data.aspx";
            if (typeof ids !== "object") {
                var tids = ids;
                ids = new Array();
                ids.push(tids);
            }
            var wordTemplateId = wordtemplateid;//"f1f7b994-543b-e711-8106-c4346bac2908" test data;
            var currentEntityTypeCode = entitytypecodeint;//"10063" test data;
            var templateType = (templatetype || 9940); //9940 is global and 9941 is personal
            var fieldForFileName = (fieldforfilename || "");
            var formdata = "exportType=MergeWordTemplate&selectedRecords=" + encodeURIComponent(JSON.stringify(ids)) +
            "&associatedentitytypecode=" + currentEntityTypeCode + "&TemplateId=" + wordTemplateId + "&TemplateType=" + templateType;
            var req = new XMLHttpRequest();
            req.open("POST", funcpath, true);
            req.responseType = "arraybuffer";
            req.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
            req.setRequestHeader("Accept-Language", "en-US,en;q=0.8");
            req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            req.onreadystatechange = function () {
                if (this.readyState == 4) {/* complete */
                    req.onreadystatechange = null;
                    if (this.status >= 200 && this.status <= 299) {//200 range okay
                        var mimetype = (2 === 2) ? "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                        var blob = new Blob([req.response], { type: mimetype });
                        var fileNameTemplate = req.getResponseHeader('content-disposition').split('filename=')[1].replace(/'/g, "");
                        var dloadurl = URL.createObjectURL(blob);
                        var filename = (fieldForFileName !== "" && Xrm.Page.getAttribute(fieldForFileName) !== null && Xrm.Page.getAttribute(fieldForFileName).getValue() !== "") ?
                            Xrm.Page.getAttribute(fieldForFileName).getValue() : fileNameTemplate;
                        filename = filenameoverride || filename;
                        //new code, prevent IE errors
                        if (navigator.msSaveOrOpenBlob) {
                            navigator.msSaveOrOpenBlob(blob, filename);
                            return;
                        }
                        else if (window.navigator.msSaveBlob) { // for IE browser
                            window.navigator.msSaveBlob(blob, filename);
                            return;
                        }
                        var a = document.createElement("a");
                        document.body.appendChild(a);
                        a.style = "display: none";
                        a.href = dloadurl;
                        a.download = filename;
                        a.click();
                        URL.revokeObjectURL(dloadurl);
                        //window.location = dloadurl;//we can use just this instead of creating an anchor but we don't get to the name the file
                    }
                    else {
                        Xrm.Page.ui.setFormNotification("An Error occurred generating the word document, please contact support if the issue persists,code: " + this.status, "ERROR", "worderror");
                    }
                }
            };
            req.send(formdata);
        }
        catch (err) {
            Xrm.Page.ui.setFormNotification("An Error occurred generating the word document, please contact support if the issue persists. " + err.message, "ERROR", "worderror");
        }

    }

Когда вы щелкаете всплывающее окно шаблонов, оно динамически заполняется вызовом /AppWebServices/DocumentTemplate.asmx, который возвращает XML для меню.

Всплывающее окно для шаблонов Word в сетке домашней страницы Incident выглядит следующим образом:

<Menu Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu">
    <MenuSection Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu.CreateTemplates" Title="Create Word Template" Sequence="10" DisplayMode="Menu16">
        <Controls Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu.CreateTemplates.Controls">
            <Button Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu.CreateTemplates.Controls.00000000-0000-0000-0000-000000000000" Command="incident|NoRelationship|HomePageGrid|Mscrm.WordTemplate.CreateWordTemplate.Grid" Sequence="10" ToolTipDescription="Create Word Template" Alt="Create Word Template" LabelText="Create Word Template" />
        </Controls>
    </MenuSection>
    <MenuSection Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu.WordTemplates" Title="Word Templates" Sequence="20" DisplayMode="Menu16">
        <Controls Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu.WordTemplates.Controls">
            <Button Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu.WordTemplates.Controls.9b77c5b0-1033-4741-a01c-afdbdb1c3f22" Command="incident|NoRelationship|HomePageGrid|Mscrm.WordTemplate.TemplatesMenu.Grid" Sequence="10" ToolTipDescription="Case Summary" Alt="Case Summary" LabelText="Case Summary" />
        </Controls>
    </MenuSection>
</Menu>

У меня нет средств, чтобы попробовать это в данный момент, но я бы попытался "скопировать" последний <Button>:

<Button Id="incident|NoRelationship|HomePageGrid|Mscrm.HomepageGrid.incident.WordTemplates.Menu.WordTemplates.Controls.9b77c5b0-1033-4741-a01c-afdbdb1c3f22" Command="incident|NoRelationship|HomePageGrid|Mscrm.WordTemplate.TemplatesMenu.Grid" Sequence="10" ToolTipDescription="Case Summary" Alt="Case Summary" LabelText="Case Summary" />

Это можно сделать, используя только поддерживаемые функции CRM (конечно, я уверен, что можно также использовать неподдерживаемый javascript, но у меня нет времени, чтобы исследовать это). Шаги, которые вы должны предпринять для достижения желаемой функциональности:

  1. Создайте новый процесс типа Action, связанный с сущностью, для которой вы хотите создать шаблон (причина, по которой я предлагаю Action здесь, заключается в том, что он может быть легко вызван с использованием JavaScript и CRM WebAPI)
  2. В этом действии добавьте один шаг - вызовите действие и выберите встроенное действие "SetWordTemplate"
  3. Задайте свойства этого действия - выберите нужный шаблон и динамически установите целевой объект для текущей сущности (с помощью помощника по динамическим значениям). Если вы никогда не использовали это действие - он просто создает данный шаблон слова и добавляет его в качестве аннотации к вашей сущности.
  4. Теперь вам нужно написать логику внутри вашей кнопки (я предполагаю, что вы знаете, как добавить кнопку с помощью Ribbon Workbench или чего-то еще)
  5. Вызовите свое действие, используя WebAPI
  6. Найти аннотацию, которая была только что создана для вашей сущности с приложенным документом
  7. Загрузите вложение (вы можете показать пользователю подсказку или просто принудительно загрузить файл, пользователю придется сохранить его)
  8. Удалить аннотацию

Может быть, не один вкладыш, но держит вас в поддерживаемой зоне...

Просто чтобы упростить @TeamEASI.com, ответьте немного, вот что я сделал.

  1. Добавьте кнопку на ленту с помощью XRMToolBox Ribbon Workbench 2016. добавить кнопку на ленту
  2. Создайте веб-ресурс JS, как показано ниже.

/*
* Author:      Matthew Hunt
* File:        vsi_DownloadTemplate.js
* Date:        12/20/2017
* Project:     CRM USA
* Description: DownloadTemplate() allows the user to download a document template 
* via a button on the ribbon.
*
* @param entitytypecode: the type code of the entity. In the ribbon workbench set a
* CRM parameter with value PrimaryEntityTypeCode. ex: 1063
*
* @param  templateid: the id for the template you want to download. I had to go to 
* the database to find this and pass it as a string parameter in the ribbon workbench.
* For example: 
* SELECT DocumentTemplateId, Name FROM dbo.DocumentTemplateBase WHERE Name Like '%Quote%';
* returns something like 4AB391A4-D247-E711-80D3-005056914EA2
* Unforunatly, anytime the template is updated, you'll probably have to get the new id.
*
* @param templatetype: the code for the template type. Pass this value in the ribbon 
* workbench as a int param. ex: 9940 is a documenttemplate
* 
* @param filename: the resulting name of the file that will be downloaded to the users 
* computer. Pass this value in the ribbon workbench as a string param. ex: Quote.docx
*
*/
function DownloadTemplate(entitytypecode, templateid, templatetype, filename){
    
    // retrieve the entity id from the current page
    var entityid = new Array();
    entityid.push(Xrm.Page.data.entity.getId());
    
    // try and make a request for the document template
    try{
        
        // clear the page of any previous errors
        Xrm.Page.ui.clearFormNotification("docerror");
        
        // the path that will be used to retrieve the word template
        var funcpath = Xrm.Page.context.getClientUrl() + "/_grid/print/print_data.aspx";
        
        // open the request to create the template
        var req = new XMLHttpRequest();
        req.open("POST", funcpath, true);
        req.responseType = "arraybuffer";
        req.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        req.setRequestHeader("Accept-Language", "en-US,en;q=0.8");
        req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        
        // on completion, run the bellow function
        req.onreadystatechange = function () {
            // request complete
            if (this.readyState == 4) {
                req.onreadystatechange = null;
                 // check if we got back a 200 from the request
            if (this.status >= 200 && this.status <= 299) {
                
                // add the download url to an a tag and then click the a tag 
                // to download the document
                var mimetype = (2 === 2) ? "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                var blob = new Blob([req.response], { type: mimetype });
                var dloadurl = URL.createObjectURL(blob);
                var a = document.createElement("a");
                
                // if ie, because ie sucks
                if (navigator.msSaveOrOpenBlob) {
                    navigator.msSaveOrOpenBlob(blob, filename);
                    
                // else a browser that doesn't suck
                } else {
                    document.body.appendChild(a);
                    a.style = "display: none";
                    a.href = dloadurl;
                    a.download = filename;
                    a.click();
                    URL.revokeObjectURL(dloadurl);
                }
                
            }
        };
        
        // compile the data to send with the request
        var formdata = "exportType=MergeWordTemplate&selectedRecords=" + encodeURIComponent(JSON.stringify(entityid)) +
        "&associatedentitytypecode=" + entitytypecode + "&TemplateId=" + templateid + "&templatetype=" + templatetype;
        
        // make the request to create the template
        req.send(formdata);
        
    }catch (err) {
        PrintError(err.message);
    }
}

/*
* PrintError() is a helper method to display any errors to the user.
*/
function PrintError(msg){
    Xrm.Page.ui.setFormNotification("An Error occurred generating the word document, please contact support if the issue persists. " + msg, "ERROR", "docerror");
}

Исправление IE: .click (), предоставляющий доступ, запрещенный в IE11

  1. Создайте команду с помощью XRMToolBox Ribbon Workbench 2016 со следующими параметрами для выполнения JS при нажатии кнопки. Скачать команду

В новой версии CRM этот код javascript необходимо изменить, чтобы удалить неподдерживаемый API, а также некоторые дополнительные изменения, чтобы можно было работать также с CHROME.

ниже моей рабочей версии,

      /*
 * Author:      Matthew Hunt
 * Changes:     Philippe Guarino
 * File:        vsi_DownloadTemplate.js
 * Date:        22/09/2021
 * Project:     CRM USA
 * Description: DownloadTemplate() allows the user to download a document template
 * via a button on the ribbon.
 *
 * @param entitytypecode: the type code of the entity. In the ribbon workbench set a
 * CRM parameter with value PrimaryEntityTypeCode. ex: 1063
 *
 * @param  templateid: the id for the template you want to download. I had to go to
 * the database to find this and pass it as a string parameter in the ribbon workbench.
 * For example:
 * SELECT DocumentTemplateId, Name FROM dbo.DocumentTemplateBase WHERE Name Like '%Quote%';
 * returns something like 4AB391A4-D247-E711-80D3-005056914EA2
 * Unforunatly, anytime the template is updated, you'll probably have to get the new id.
 *
 * @param templatetype: the code for the template type. Pass this value in the ribbon
 * workbench as a int param. ex: 9940 is a documenttemplate
 *
 * @param filename: the resulting name of the file that will be downloaded to the users
 * computer. Pass this value in the ribbon workbench as a string param. ex: Quote.docx
 *
 */

function DownloadTemplate(entitytypecode, templateid, templatetype, filename, formContext)
{
//  var formContext = executionContext.getFormContext(); // get formContext
    // retrieve the entity id from the current page
    var entityid = new Array();
    entityid.push(formContext.data.entity.getId());
    // try and make a request for the document template
    try
    {
        // clear the page of any previous errors
        formContext.ui.clearFormNotification("docerror");
        // the path that will be used to retrieve the word template
        var globalContext = Xrm.Utility.getGlobalContext();
        var funcpath = globalContext.getClientUrl() + "/_grid/print/print_data.aspx";;
        // open the request to create the template
        var req = new XMLHttpRequest();
        req.open("POST", funcpath, true);
        req.responseType = "arraybuffer";
        req.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        req.setRequestHeader("Accept-Language", "en-US,en;q=0.8");
        req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        // on completion, run the bellow function
        req.onreadystatechange = function ()
        {
            // request complete
            if (this.readyState == 4)
            {
                req.onreadystatechange = null;
                // check if we got back a 200 from the request
                if (this.status >= 200 && this.status <= 299)
                {
                    // add the download url to an a tag and then click the a tag 
                    // to download the document
                    var mimetype = (2 === 2) ? "application/vnd.openxmlformats-officedocument.wordprocessingml.document" : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                        var blob = new Blob([req.response],
                    {
                        type: mimetype
                    });
                    

                    
                    var dloadurl = (window.URL ? URL : webkitURL).createObjectURL(blob);
                    var a = document.createElement("a");
                    // if ie, because ie sucks
                    if (navigator.msSaveOrOpenBlob)
                    {
                        navigator.msSaveOrOpenBlob(blob, filename);
                        // else a browser that doesn't suck
                    }
                    else
                    {
                        document.body.appendChild(a);
                        a.style = "display: none";
                        a.href = dloadurl;
                        a.download = filename;
                        a.click();
                        URL.revokeObjectURL(dloadurl);
                    }                
                }
            }
        };
        
    // compile the data to send with the request
            var formdata = "exportType=MergeWordTemplate&selectedRecords=" + encodeURIComponent(JSON.stringify(entityid)) +
                "&associatedentitytypecode=" + entitytypecode + "&TemplateId=" + templateid + "&templatetype=" + templatetype;
            // make the request to create the template
            req.send(formdata);
            
    }
    catch (err)
    {
        PrintError(err.message);
    }
}
/*
 * PrintError() is a helper method to display any errors to the user.
 */

function PrintError(msg)
{
      Xrm.Page.ui.setFormNotification("An Error occurred generating the word document, please contact support if the issue persists. " + msg, "ERROR", "docerror");
}

Для всех, кто хочет создавать текстовые документы из JS в Dyn365 Online;

В Интернете вы можете найти «список недокументированных сообщений SDK» для Dynamics (НАЖМИТЕ). Он не поддерживается, но сейчас работает.

из-за своей внутренней природы они могут устареть в будущих выпусках CRM без какого-либо уведомления со стороны Microsoft.

Благодаря этому я готовлю пример кода для загрузки шаблонов Word (вам нужно только поместить его в функцию, изменить такие параметры, как EntityTypeCode, templateid, имя файла... и т. д.).

Чтобы получить код объекта, запустите следующий запрос:

SELECT coalesce(OriginalLocalizedName,name) AS DisplayName, Name AS SchemaName, ObjectTypeCode
FROM EntityLogicalView
ORDER BY ObjectTypeCode

и для Template ID:

SELECT DocumentTemplateId, Name FROM dbo.DocumentTemplateBase
Другие вопросы по тегам