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: , , , , ,

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading

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