Criar um botão de cancelar para a Proposta

by Pedro Azevedo 7. November 2014 07:53

Boas pessoal,

O fórum ataca novamente Cool e foi colocada a seguinte questão. Quando temos uma proposta e criamos uma encomenda, a proposta fica num estado final como Ganha. Se por algum motivo a encomenda não se efetuar o Dynamics CRM permite o seu cancelamento:

A questão prende-se se quisermos cancelar a Proposta também e o que se constata é que não é possível realizar essa operação, apenas existe a opção eliminar:

Penso que a opção eliminar é muito drástica, e já agora ele não vai deixar porque existe a ligação com a encomenda. Então o objetivo de hoje é realizarmos um botão de cancelar. A nível funcional para algumas empresas não fará sentido eu mexer na proposta, já que se ela foi no fundo adjudicada então não devemos mudar o estado para sabermos que este negócio foi cancelado aquando da encomenda. Mas neste caso é apontado como uma incoerência de dados o que também se pode justificar.

Para começar nada melhor que verificarmos como é que mensagens temos para mudar o estado, todo o trabalho poderia ser feito com a mensagem SetStateRequest em que passamos qual o State e o Status que queremos que a proposta fique. Mas para podermos fechar a Proposta necessitamos de recorrer a mensagem CloseQuoteRequest, vejam o erro que ele dá se utilizarmos esta estratégia (SetStateRequest):

This message can not be used to set the state of quote to Closed. In order to set state of quote to Closed, use the CloseQuoteRequest message instead.

Para sermos brutos vamos tentar fechar a Proposta diretamente com o CloseQuoteRequest, como é de esperar ele não deixa pois temos que seguir o fluxo de estados estabelecido para a Proposta:

 E já agora vamos rever quais os valores que estão para cada um destes estados:

Estado

Valor

Razão do Estado

Valor

Ativo

1

Em progresso

Aberto

2

3

Fechado

3

Perdido

Cancelado

Revisto

5

6

7

Rascunho

0

Em Progresso

1

Ganha

2

Ganha

4

Vamos ver a mensagem que dá se mesmo assim insistirmos nesta estratégia, fechado através do CloseQuoteRequest estando a proposta num estado final:

The entity cannot be closed because it is not in the correct state.

Para colocarmos a Proposta em rascunho teremos que efetuar a seguinte chamada:

function SetStateRequest(state, status) {
     var recordId = Xrm.Page.data.entity.getId();

     var requestMain = ""
     requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
     requestMain += "  <s:Body>";
     requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
     requestMain += "      <request i:type=\"b:SetStateRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
     requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
     requestMain += "          <a:KeyValuePairOfstringanyType>";
     requestMain += "            <c:key>EntityMoniker</c:key>";
     requestMain += "            <c:value i:type=\"a:EntityReference\">";
     requestMain += "              <a:Id>" + recordId.replace('{', '').replace('}', '') + "</a:Id>";
     requestMain += "              <a:LogicalName>quote</a:LogicalName>";
     requestMain += "              <a:Name i:nil=\"true\" />";
     requestMain += "            </c:value>";
     requestMain += "          </a:KeyValuePairOfstringanyType>";
     requestMain += "          <a:KeyValuePairOfstringanyType>";
     requestMain += "            <c:key>State</c:key>";
     requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
     requestMain += "              <a:Value>" + state + "</a:Value>";
     requestMain += "            </c:value>";
     requestMain += "          </a:KeyValuePairOfstringanyType>";
     requestMain += "          <a:KeyValuePairOfstringanyType>";
     requestMain += "            <c:key>Status</c:key>";
     requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
     requestMain += "              <a:Value>" + status + "</a:Value>";
     requestMain += "            </c:value>";
     requestMain += "          </a:KeyValuePairOfstringanyType>";
     requestMain += "        </a:Parameters>";
     requestMain += "        <a:RequestId i:nil=\"true\" />";
     requestMain += "        <a:RequestName>SetState</a:RequestName>";
     requestMain += "      </request>";
     requestMain += "    </Execute>";
     requestMain += "  </s:Body>";
     requestMain += "</s:Envelope>";
     var req = new XMLHttpRequest();
     req.open("POST", _getServerUrl(), false)
     // Responses will return XML. It isn't possible to return JSON.
     req.setRequestHeader("Accept", "application/xml, text/xml, */*");
     req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
     req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
     var successCallback = null;
     var errorCallback = null;
     req.onreadystatechange = function () { ResponseOK(req); };
     req.send(requestMain);
 }

Para colocar em rascunho:

function putQuoteInDraft(){
     SetStateRequest(0, 1);
 }

Neste momento temos a Proposta em Rascunho, para verificarmos mais uma vez o fluxo de estados vamos tentar ativar a Proposta estando esta no estado final, mais uma vez recebemos uma mensagem de erro:

 The quote cannot be activated because it is not in draft state

Então temos que ativar a nossa Proposta com o seguinte código:

function putQuoteInActive(){
     SetStateRequest(1, 3);
 }

E com isto temos a nossa Proposta ativada e com a razão de estado em aberta. Agora sim podemos fechar a nossa Proposta e com a razão cancelado. Para isso efetuamos a seguinte chamada:

function CloseQuoteRequest(status, msg) {
     var recordId = Xrm.Page.data.entity.getId();

     var requestMain = ""
     requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
     requestMain += "  <s:Body>";
     requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
     requestMain += "      <request i:type=\"b:CloseQuoteRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
     requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
     requestMain += "          <a:KeyValuePairOfstringanyType>";
     requestMain += "            <c:key>QuoteClose</c:key>";
     requestMain += "            <c:value i:type=\"a:Entity\">";
     requestMain += "              <a:Attributes>";
     requestMain += "                <a:KeyValuePairOfstringanyType>";
     requestMain += "                  <c:key>quoteid</c:key>";
     requestMain += "                  <c:value i:type=\"a:EntityReference\">";
     requestMain += "                    <a:Id>" + recordId.replace('{', '').replace('}', '') + "</a:Id>";
     requestMain += "                    <a:LogicalName>quote</a:LogicalName>";
     requestMain += "                    <a:Name i:nil=\"true\" />";
     requestMain += "                  </c:value>";
     requestMain += "                </a:KeyValuePairOfstringanyType>";
     requestMain += "                <a:KeyValuePairOfstringanyType>";
     requestMain += "                  <c:key>subject</c:key>";
     requestMain += "                  <c:value i:type=\"d:string\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">" + msg + "</c:value>";
     requestMain += "                </a:KeyValuePairOfstringanyType>";
     requestMain += "              </a:Attributes>";
     requestMain += "              <a:EntityState i:nil=\"true\" />";
     requestMain += "              <a:FormattedValues />";
     requestMain += "              <a:Id>00000000-0000-0000-0000-000000000000</a:Id>";
     requestMain += "              <a:LogicalName>quoteclose</a:LogicalName>";
     requestMain += "              <a:RelatedEntities />";
     requestMain += "            </c:value>";
     requestMain += "          </a:KeyValuePairOfstringanyType>";
     requestMain += "          <a:KeyValuePairOfstringanyType>";
     requestMain += "            <c:key>Status</c:key>";
     requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
     requestMain += "              <a:Value>" + status + "</a:Value>";
     requestMain += "            </c:value>";
     requestMain += "          </a:KeyValuePairOfstringanyType>";
     requestMain += "        </a:Parameters>";
     requestMain += "        <a:RequestId i:nil=\"true\" />";
     requestMain += "        <a:RequestName>CloseQuote</a:RequestName>";
     requestMain += "      </request>";
     requestMain += "    </Execute>";
     requestMain += "  </s:Body>";
     requestMain += "</s:Envelope>";
     var req = new XMLHttpRequest();
     req.open("POST", _getServerUrl(), false)
     // Responses will return XML. It isn't possible to return JSON.
     req.setRequestHeader("Accept", "application/xml, text/xml, */*");
     req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
     req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
     var successCallback = null;
     var errorCallback = null;
     req.onreadystatechange = function () { ResponseOK(req); };
     req.send(requestMain);
 }

A chamada desta função é a seguinte:

function putQuoteInCancel(){
     CloseQuoteRequest(6, "Cancelado porque a encomenda foi cancelada");
 }

Uma das razões que o SetStateRequest não funciona é que o fecho da Proposta necessita de um objeto QuoteClose onde guarda por exemplo a mensagem que estamos a passar.

Agora que temos a sequência de chamada estabelecida só nos falta criamos o botão, aqui mais uma vez e sem dúvida nenhum vamos recorrer ao RibbonWorkBench já muito referenciado aqui no blog. Por isso vou encurtar os screens desta parte. Resumidamente temos que:

  • Adicionar um botão a barra de comandos, neste caso a tab que diz Form;
  • Dentro deste botão, podemos colocar um novo texto e um icon;
  • Mas o mais importante no botão é associarmos um comando;

·         Este comando é onde está configurado quais os passos a executar e quais os critérios de Display e Enable:


 

Como podem reparar tenho as várias chamadas aos métodos que refiro acima e pela ordem correta.

Vou só colocar as funções auxiliares que usei:

function _getServerUrl() {
     var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
     var serverUrl = "";
     if (typeof GetGlobalContext == "function") {
          var context = GetGlobalContext();
          serverUrl = context.getServerUrl();
     }
     else {
          if (typeof Xrm.Page.context == "object") {
               serverUrl = Xrm.Page.context.getServerUrl();
          }
          else{ 
               throw new Error("Unable to access the server URL"); }
          }
          if (serverUrl.match(/\/$/)) {
             serverUrl = serverUrl.substring(0, serverUrl.length - 1);
     } 
     return serverUrl + OrgServicePath;
}

 function ResponseOK(req) {
       if (req.readyState == 4) {
       if (req.status == 200) {
       }
       else {
           alert('erro');
       }
   }
}

function refreshForm(){
     var recordId = Xrm.Page.data.entity.getId();
     Xrm.Utility.openEntityForm("quote", recordId);
}

 

Se tiverem alguma dúvida coloquem nos comentários ou vão até ao fórum.

 

 

Até a próxima

Tags: , , , , ,

Esconder botão dinâmicamente ribbon ou barra de comandos

by Pedro Azevedo 19. February 2014 23:30

Boas Pessoal,

Já queria fazer este post há muito tempo, mas fui adiando e nunca cheguei a criar sobre a versão CRM 2011. Por isso estou agora a fazê-lo sobre a versão CRM 2013 mas é similar a anterior, por isso poderão aplicar os mesmos conceitos sobre o CRM 2011.

Criei neste momento por causa de uma dúvida nos fóruns do MSDN, em que se quer inibir a criação de uma encomenda numa proposta. Neste caso o critério é que a razão de estado da oportunidade esteja preenchida e tem como requisito que seja feito via Javascript e não por plugin.

Para além de responder a questão do fórum este post tem como objetivo de ser um manual genérico para desabilitar um botão dinamicamente.

Bom o primeiro requisito é instalar esta ferramenta que podem ver aqui um pequeno manual.

A primeira coisa a fazer é criar uma solução que tenha a entidade Proposta (quote), depois desta solução criada teremos que fazer load dela na Ribbon Workbench e terá um layout deste género:

 

O que nós queremos é o botão que temos selecionado “Create Order” estar visível apenas quando uma determinada função Javascript retornar true. Para isso sobre este botão “Create Order” e com o botão direito do rato, carregar “Customise Button”, quando fazemos isto ele deve acrescentar o comando de criar encomenda na tab “Solution Elements”:

Para já aqui é tudo, voltamos mais a frente. Agora vamos criar uma regra de enable, na entrada “Enable Rules” escolham “Add New”:

 

Ele cria uma nova entrada, se quiserem podem modificar o nome, sobre esta nova entrada carreguem em “Add Rule”:

 

Com isto deve aparecer uma lista de regras que podemos aplicar, no nosso caso será uma regra de Javascript.

 

Depois de confirmarmos que queremos uma regra de Javascript, basta dizer qual a função a ser chamada e sobre qual o recurso web queremos aplicar.

Como podem comprovar vou chamar a função Javascript enablequotebutton do recurso web que especifiquei, este recurso web terá que estar na solução que carregamos dentro da ferramenta, neste caso na solução TesteRibbon.

O código presente neste webresource é o seguinte:

function enablequotebutton(){
  LoadWebResource('new_json');
  LoadWebResource('new_jquery');
  LoadWebResource('new_xrmservicetoolkit');
 
  var opId = Xrm.Page.getAttribute("opportunityid").getValue()[0].id;
  var cols = ["statuscode"];
  var retrievedOpportunity = XrmServiceToolkit.Soap.Retrieve("opportunity", opId, cols);

  if(retrievedOpportunity.attributes["statuscode"].value != 1){
    return true;
  }
  else{
    return false;
  }
}

function LoadWebResource(resource) {
  httpRequest = new XMLHttpRequest();
  httpRequest.open("GET", "/webresources/" + resource, false);
  httpRequest.send(null);
  try
    {
      eval(httpRequest.responseText); 
    }
    catch (e)
    {
      alert("Erro");
    }
}

Como podem ver no troço de código anterior estou a utilizar uma função auxiliar para poder carregar bibliotecas Javascript, pois estou a utilizar a biblioteca XrmServiceToolkit para poder ir buscar propriedades da oportunidade associada a proposta.

Depois disto não esqueçam de publicar a solução na Ribbon Workbench.

Até a próxima.

Tags: , , , , ,

CRM 2013 - Restaurar botão "Executar Relatorio"

by Pedro Azevedo 3. January 2014 02:57

 Boas pessoal,

Nas minhas aventuras pelo CRM 2013 reparei que o botão de executar relatório não estava presente na entidade proposta e encomenda. O mais estranho é que na lista de propostas este botão está presente, mesmo quando selecionamos uma proposta, por isso para mim isto não fazia sentido. Então fui a procura de uma solução e encontrei este post que explica como mostrar o botão que criar ligações.

Então vou fazer a mesma coisa para a execução do relatório. Para vermos o comportamento reparem na diferença entre a lista e o próprio registo:

Como podem comprovar o botão não se encontra disponível dentro do registo. Então vamos ver como o podemos voltar a mostrar este botão, primeiro vamos recorrer a ferramenta Ribbon Workbench. Nesta ferramenta e como eu refiro no post de introdução a esta tarefa podemos restaurar botões que estavam presentes na ribbon.

Depois de fazermos load da solução que deve conter a entidade proposta (quote) e selecionarmos a tab da ribbon vemos a ribbon que aparecia no CRM 2011. No seletor vamos mudar para formulário, porque queremos mostrar quando abrimos um registo. Aqui vamos selecionar o botão “Run Report” com o botão direito do rato e escolher a opção “Customize Command”, o que vai aparecer aquela entrada nos comandos. Com o botão direito do rato este comando vamos escolher a opção “Edit Display Rules”, aqui vamos ver logo uma entrada sugestiva “Mscrm.HideOnCommandBar”. Então basta seleccionarmos esta entrada e carregar no “Remove”.

 

Agora basta publicar esta solução e ao acedermos novamente ao registo vamos passar a ver esta entrada.

Até a próxima.

Tags: , ,

Ferramenta - Ribbon Workbench

by Pedro Azevedo 6. December 2013 08:05

 Boas pessoal,

Inicio agora formalmente uma nova série de posts, que tem como objetivo mostrar as várias ferramentas\utilitários\bibliotecas disponíveis para o CRM e que tem como objetivo auxiliar-nos no dia-a-dia. A primeira “vítima” foi a biblioteca XrmServiceToolkit.

Hoje vou apresentar uma ferramenta muito útil e que não se pode viver sem ela. Estou a falar da ferramenta Ribbon Workbench. Como o próprio nome denúncia serve para customizar a Ribbon. Existem outras alternativas, tais como, Ribbon Editor, Pragma Toolkit e Visual Ribbon Editor mas a que mais utilizo é realmente a Ribbon Workbench. Esta já suporta CRM 2013 as outras ferramentas não tenho a certeza.

Para instalar basta ir a página http://www.develop1.net/public/page/Ribbon-Workbench-for-Dynamics-CRM-2011.aspx aqui temos várias informações e podemos escolher sobre qual versão do CRM queremos trabalhar.

Em ambos os casos vai fazer download da solução que devemos instalar na nossa organização. Depois de instalarmos a solução devemos ter a seguinte visualização:

Para aceder é selecionar o botão “Personalizado” no CRM 2011 tem o seguinte aspecto:

Depois de entrarmos no Ribbon Workbench temos que escolher a solução quer queremos customizar, por isso, já temos que ter criado uma solução e que esta inclua a entidade sobre a qual queremos customizar a ribbon, neste caso concreto adicionei a entidade Proposta (quote).

 

Depois de carregar a solução temos o seguinte aspecto:

Vamos então analisar cada uma destas secções individualmente:

 

Aqui vemos quais os botões que são possíveis de ver nas várias visualizações:

·         Home – é o menu que é mostrado nos ecrãs principais.

·         Sub-Grid – menu que é mostrado quando selecionamos uma subgrid, ou seja, no CRM 2011 sempre que selecionavamos uma subgrid a ribbon mudava para o contexto da entidade da subgird. No CRM 2013 não existe esta funcionalidade. Quer dizer existir existe por exemplo quando estamos num cliente e se virmos a lista de contactos:

 

Quando carregamos na lista aparece a lista em baixo:

 

Onde aqui aparece este menu.

·         Form – menu que aparece quando abrimos um registo de uma entidade.

De referir que temos a opção de ver a ribbon que aparece no cliente para o Outlook e que por ter a mesma estrutura que a barra de comandos e como vamos ver em futuros posts nós conseguimos recorrendo a ribbon acrescentar botões que não existem na barra de comandos.

Na próxima secção mostra os vários controlos que poderemos inserir na barra de comandos:

 

O tab permite agrupar botões, a tab scale define como os botões mudam quando existem retrições de tamanho. O grupo permite dar contexto a um conjunto de botões dentro de um determinado tab. E depois os vários tipos de botões, ou seja, Button, Split Button e Flyout. O Menu Section é o chamado Jewel Menu, que basicamente é o menu File que aparece no CRM 2011.

No CRM 2013 temos mais algumas definições. Na imagem estamos a ver a barra de comandos que pode mostrar até 5 comandos, os três pontos permite expandir as opções e é designado por overflow. Dentro da barra de comandos podemos ver os botões “normais”, os botões flyout podem estar dentro da barra de comandos e dentro do overflow:

 

Na secção final que vamos analisar temos as acções que poderemos realizar sobre os botões:

 

Na lista de entidades vemos as entidades que estavam na solução que escolhemos quando lançamos a ferramenta. Na lista ao lado temos os elementos da solução, incluindo os comandos que são executados, bem como as regras de mostrar ou não os botões. Este assunto dava para um livro por isso eu demonstrando nos vários posts que pretendo criar.

A última lista estão as propriedades dos elementos gráficos ou dos comandos ou regras.

A última acção e a mais importante é publicarmos as mudanças que realizamos, para isso basta carregar no botão "Publish".

Espero que tenham ficado com uma ideia desta magnifica ferramenta, um bem haja ao Scott Durow. Em futuros posts eu vou demonstrar como podemos acrescentar, esconder botões.

Até a próxima.

Tags: , , ,

About

Muito bem casado, Pai babado e um gosto muito grande pela tecnologia.

Tenho um lema "Sharing is Learning"

Mais aqui -> http://www.psazevedo.com

Month List