CRM 2013 SP1 UR3

by Pedro Azevedo 27. April 2015 13:55

Boas Pessoal,

Mais um update disponível para os ambiente On-Premise desta vez para a versão CRM 2013, reparem que novamente existe a referência ao Update Rollup, lembro que a partir da versão Dynamics CRM 2015 Update 0.1 o termo rollup já não existe.

Mais uma vez este rollup trás inúmeras correções de bugs e melhorias de segurança e estabilidade, vejam aqui mais detalhes e façam download nesta página.

Até a próxima

Tags: , ,

CRM 2013 SP1 – UR2

by Pedro Azevedo 11. February 2015 13:39

Boas pessoal,

Foi disponibilizado o UR2 do CRM 2013 SP1 Este rollup pode-se transferir aqui. Para mais informações podem ver aqui, este rollup contém mais 100 issues resolvidos.

Até a próxima.

Tags: , , ,

CRM 2013 Javascript Object Model - Control

by Pedro Azevedo 30. November 2014 22:04

Boas pessoal,

Hoje na sequência dos posts do object model do Javascript, desta vez vamos ver as opções que temos ao nível do controlo.

getAttribute

function getAttributeTest() {
	Xrm.Utility.alertDialog(Xrm.Page.getControl("subject").getAttribute().getValue());
}

getControlType

Valores possíveis de retorno:

Return Value

Description

standard

A Standard control.

iframe

An IFRAME control

lookup

A Lookup control.

optionset

An OptionSet control

subgrid

A subgrid control

webresource

A web resource control

notes

A Notes control

function getControlTypeTest() {
	Xrm.Utility.alertDialog(Xrm.Page.getControl("subject").getControlType());
}

getDisabled

function getDisabledTest() {
	Xrm.Utility.alertDialog("subject está com disabled a " + Xrm.Page.getControl("subject").getDisabled());
	Xrm.Utility.alertDialog("lastusedincampaign está com disabled a " + Xrm.Page.getControl("lastusedincampaign").getDisabled());
}

setDisabled

function setDisabledTest() {
	Xrm.Page.getControl("subject").setDisabled(true);
} 

getLabel

function getLabelTest() {
	Xrm.Utility.alertDialog(Xrm.Page.getControl("subject").getLabel());
}

setLabel

function setLabelTest() {
	Xrm.Page.getControl("subject").setLabel("Nova Label");
}

getName

function getNameTest() {
	Xrm.Utility.alertDialog(Xrm.Page.getControl("subject").getName());
}

getParent

Dá a secção onde está dentro.

function getParentTest() {
	Xrm.Utility.alertDialog(Xrm.Page.getControl("subject").getParent().getLabel ());
} 

getVisible

function getVisibleTest() {
	Xrm.Utility.alertDialog("O controlo subject está com visible a " + Xrm.Page.getControl("subject").getVisible());
}

setVisible

function setVisibleTest() {
	Xrm.Page.getControl("subject").setVisible(false);
}

setFocus

function setFocusTest() {
	Xrm.Page.getControl("subject").setFocus(true);
}

setNotification

function setNotificationTest() {
	Xrm.Page.getControl("subject").setNotification("Teste a função setNotification");
}

 

clearNotification

function clearNotificationTest() {
	Xrm.Page.getControl("subject").setNotification("Teste a função setNotification", "UMID");
	Xrm.Page.getControl("subject").clearNotification("UMID");
}

Até a próxima

Tags: , , ,

CRM 2013 Javascript Object Model - Lookup

by Pedro Azevedo 19. November 2014 19:50

Boas pessoal,

Continuando o conjunto de posts sobre a API de Javascript e também continuando o post de lookups no CRM 2013, hoje vou falar sobre o que temos na API de Javascript para interagir com os lookups. Este post já tinha sido feito para a versão 2011, por isso não vou voltar a falar das funções addCustomView, setDefaultView isso porque os métodos mantém os mesmos parâmetros e objetivos.

Ainda dentro dos métodos que existiam no CRM 2011, existe o getDefaultView, segue um exemplo:

function onload() {
        alert('default view->' + Xrm.Page.getControl('parentaccountid').getDefaultView());
}

Depois temos os métodos addCustomFilter, addPreSearch, removePreSearch, estes métodos com já foi dito aparecem na versão 2013. Para usar temos que fazer a combinação entre o addCustomerFilter e addPreSearch, para adicionamos um pré filtro temos que chamar o addPreSearch onde temos que adicionar um event handler que vai adicionar um filtro através do método addCustomerFilter:

function addPreFilter() {
	var city = Xrm.Page.getAttribute("address1_city").getValue();

	var filter ="<filter type='and'>" +
	             "<condition attribute='address1_city' operator='eq' value='" + city + "'/>" +
	             "</filter>";

	Xrm.Page.getControl("parentaccountid").addCustomFilter(filter);
}


function addPreSearchFilter() {
	Xrm.Page.getControl("parentaccountid").addPreSearch(addPreFilter);
}

Vejam as imagens em que na primeira não existe qualquer pré-filtro e na segunda aplicando o método anterior, ou seja, em vez de aparecer todos os registos consegue-se aplicar um filtro mais eficaz e com mais possibilidade de escolher sem ter que abrir uma nova janela.

 

Para se retirar este pré filtro temos que chamar o método removePreSearch e passar o event handler que passamos no método addPreSearch.

function removePreSearchFilter() {
	Xrm.Page.getControl("parentaccountid").removePreSearch(addPreFilter);
}

Este métodos podem ser de grande ajuda quando bem utilizados.

 

Até a próxima

Tags: , , , , ,

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

Executar um FetchXML e exportar para CSV com Javascript

by Pedro Azevedo 19. October 2014 16:12

 

Boas pessoal,

Hoje um post muito rápido de como executar um FetchXML e exportar os resultados para um CSV, tudo isto em Javascript.

Para começar é possível executar um FetchXML através de uma requisição SOAP. Quando tenho este tipo de requisição recorro a biblioteca XrmServiceToolkit, no blog existem vários exemplos.

Para executar um FetchXml usamos a função Fetch:

function ExecuteFetch() {
    var fetchXml =
            "<fetch mapping='logical'>" +
               "<entity name='contact'>" +
                  "<attribute name='contactid' />" +
                  "<attribute name='firstname' />" +
                  "<attribute name='lastname' />" +
                  "<attribute name='middlename' />" +
                  "<filter>" +
                     "<condition attribute='parentcustomerid' operator='eq' value='" + Xrm.Page.data.entity.getId() + "' />" +
                  "</filter>" +
               "</entity>" +
            "</fetch>";

    var retrievedContacts = XrmServiceToolkit.Soap.Fetch(fetchXml);
}

Este código está preparado para correr dentro da entidade cliente, retorna todos os contactos desse cliente. A dificuldade a seguir é colocar os dados num ficheiro CSV e fazer download dele, existem várias estratégias:

var csvString = allValues.join("\n");

    var a  = document.createElement('a');
    a.href = 'data:attachment/csv,' + csvString;
    a.target = '_blank';
    a.download = 'myFile.csv';

    document.body.appendChild(a);
    a.click();

Vamos ver agora o código completo que inclui o tratamento dos dados retornados:

function ExecuteFetch() {
    var fetchXml =
            "<fetch mapping='logical'>" +
               "<entity name='contact'>" +
                  "<attribute name='contactid' />" +
                  "<attribute name='firstname' />" +
                  "<attribute name='lastname' />" +
                  "<attribute name='middlename' />" +
                  "<filter>" +
                     "<condition attribute='parentcustomerid' operator='eq' value='" + Xrm.Page.data.entity.getId() + "' />" +
                  "</filter>" +
               "</entity>" +
            "</fetch>";

    var retrievedContacts = XrmServiceToolkit.Soap.Fetch(fetchXml);

    var allValues = [];
    var strCol = "";
    var strVal = "";

    var cols = true;

     for (var i = 0; i < retrievedContacts.length; i++) {
      var attsValues = retrievedContacts[i].attributes;

      for (var att in attsValues) {
        strVal += attsValues[att].value + ";";

        if(cols){
          strCol += att + ";";
        }
      }

      if(cols){
        allValues.push(strCol);
        cols = false;
      }

      allValues.push(strVal);
      strVal = "";
    }

    var csvString = allValues.join("\n");

    var a  = document.createElement('a');
    a.href = 'data:attachment/csv,' + csvString;
    a.target = '_blank';
    a.download = 'myFile.csv';

    document.body.appendChild(a);
    a.click();
}

 

Até a próxima.

Tags: , , , ,

Gráficos no Microsoft Dynamics CRM

by Pedro Azevedo 12. October 2014 16:53

Boas pessoal,

Os fóruns de discussão têm servido de inspiração para posts que tenho realizado no blog e este não é exceção, numa thread recente foi colocada uma questão sobre os gráficos, a questão envolvia mexermos diretamente no XML e mesmo assim não consegui dar uma resposta válida, na minha opinião por limitação desta funcionalidade que apareceu no CRM 2011. Este será um post introdutório e em próximos posts explorarmos mais esta funcionalidade.

Como já referi a possibilidade de criarmos gráficos surgiu na versão 2011, onde nos possibilita de criarmos um gráfico com base num conjunto de registos, esta funcionalidade é muito poderosa pois permite-nos realizar drill-down, ver quais os registos que estão por base para aquele gráfico, mas vamos ver estes detalhes todos neste conjunto de posts.

Para começar vamos ver como acedemos a esta funcionalidade, numa lista qualquer temos uma barra lateral para abrirmos os gráficos:

Esta barra é customizável pela barra de comandos, em que podemos fixar a barra e desligar a barra de gráficos para esta entidade:

Para vermos os gráficos basta carregar sobre a barra para ela abrir:

 

Para algumas entidades já existem alguns gráficos pré-definidos, mas por exemplo para as entidades customizadas não vamos ver nenhum gráfico por defeito. De referir também que os dados que estamos a visualizar correspondem a vista que está selecionada e não para os registos todos.

Para além dos gráficos ainda podemos ver um mapa e já agora com o gráfico ancorado no topo:

 

Como opções sobre os gráficos e começando do lado esquerdo para o direito, temo um selector para escolher o relatório já gravados, depois nos ícones temos a opção de adicionar um novo gráfico, expandir ou fechar o gráfico, gravar alguma alteração e importar ou exportar o gráfico.

Neste post vamos entrar apenas na criação de gráficos:

Este é o aspecto da criação de um gráfico, temos a possibilidade de dar um nome a este gráfico, temos uma área para pré-visualizarmos os dados e depois uma área para configurarmos o gráfico:

 

 

Temos vários tipos de gráficos: colunas; barras; área; linha; circular e funil. Dentro dos três primeiros ainda temos mais três opções: “normal”, empilhado e empilhado a 100%.

Para além do tipo de gráfico podemos configurar se queremos aplicar regras para obter por x elementos superiores ou inferiores e temos por defeito as seguintes opções: 3, 5 ou um número personalizado. De referir também a última opção que vai limpar estas regras. Estas regras são úteis sobretudo quando temos muitos valores e para fixarmos um alvo concreto.

Estas opções estão disponibilizadas na configuração de uma série, onde podemos adicionar novas séries, para configurarmos temos que escolher o campo e depois qual a função de agregação que queremos aplicar:

Depois de selecionar o campo é disponibilizado opções de qual a operação de agregação que se quer aplicar, neste caso temos um campo de texto selecionado e por essa razão as operações numéricas não podem ser aplicadas. De notar a diferença entre a Contagem tudo e Não-Vazio em que a opção Não-Vazio não conta os elementos que não têm valor aplicado nesse campo.

Se escolhermos um campo do tipo data temos mais algumas opções:

 

Aqui podemos partir a data em partes do ano.

Por fim não se esqueçam de colocar uma descrição para o gráfico, dá sempre jeito para percebermos qual o seu objetivo ainda mais quando temos uma configuração importada, como vamos ver mais a frente o que vamos configurar no XML não será visível.

Depois de criarmos um gráfico, tal como acontece com as vistas não fica disponibilizado para toda a organização, por isso ficamos com outras opções sobre os gráficos “locais”:

Como podemos observar temos agora opção de editar, eliminar, atribuir e partilhar que não temos sobre um gráfico de sistema.

Vamos apenas ver um pequeno exemplo, onde queremos saber o total do orçamento por classificação por cada Oportunidade Potencial

Como podem ver estou ainda a configurar e já estou a pré-visualizar os resultados. Estes resultados são fidignos, vejam a visualização do gráfico para um utilizador:

Para criar um gráfico de sistema teremos que ir as customizações, aqui temos praticamente as mesmas opções:

Nas customizações para além de podermos criar novos gráficos podemos editar os gráficos existentes de sistema.

Este post teve como grande objetivo mostrar a configuração básica, como podem ver não temos muitas opções. Nos próximos para além da edição do XML vamos ver por exemplo onde podemos utilizar os gráficos.

 

PS: Para este post utilizei o Microsoft Dynamics CRM Online, mas os conceitos são idênticos para o CRM 2011, apenas com outra interface.

 

Até a próxima.

Tags: , , , ,

Auto Numeração no Microsoft Dynamics CRM

by Pedro Azevedo 2. October 2014 00:46

 Boas pessoal,

Esta semana vou falar sobre auto-numeração no Microsoft Dynamics CRM. Uma das dúvidas mais requisitadas nos fóruns do MSDN.

Esta funcionalidade vem por defeito no Dynamics CRM mas apenas para algumas entidades standard nomeadamente:

Sobre estas entidades podemos configurar alguns dados:

  • Prefixo – para ficar antes da numeração propriamente dita, é importante para quando esta numeração aparecer isolada nós consigamos dizer que aquela numeração corresponde neste caso aos contratos.
  • Número – Em que número começa
  • Comprimento do Sufixo – Termos um sufixo, onde temos a hipótese de termos 4, 5 ou 6 algarismos.

Podemos ainda ver um exemplo, de como fica esta numeração.

E se quisermos ter uma numeração por exemplo nas oportunidades, ou numa entidade nossa customizada? Existem algumas tools que ajudam neste trabalho por exemplo este. Mas eu penso que esta tool deixa de fazer sentido no Microsoft Dynamics CRM 2013, ainda mais a vinda do Fluxo de Trabalho síncrono onde temos um feedback imediato dessa mesma numeração. Como referência tenho sempre este artigo que tem uma implementação com o Dynamics CRM 2011. Eu no fundo vou refazer para o Dynamics CRM 2013, utilizando o CRM Online.

Para começar temos que criar uma entidade customizada para guardar a numeração:

Depois de criar a entidade vamos criar dois campos, um para o prefixo (Uma linha de texto) e outro para a numeração (Número Inteiro):

De seguida fui customizar o formulário desta entidade para podermos colocar os dois campos acima, a seguir fui então adicionar registos nesta entidade onde configurei a numeração para a entidade Lead (Oportunidade Potencial). Se quiséssemos mais entidades bastava adicionar várias linhas a esta entidade:

A seguir vamos para a entidade que queremos adicionar a numeração automática, no meu caso a Lead, onde vou uma relação (N:1) para a entidade CustomAutoNumber e um campo que vai guardar a numeração, este campo vou colocar do tipo “Uma Linha de Texto” para poder colocar o sufixo.

De seguida vamos customizar o formulário da Lead, neste caso vou acrescentar dois campos, o lookup para entidade CustoAutoNumber que é o campo correspondente a criação da relação e o campo que vai guardar a numeração. De referir que no vosso caso o melhor é não acrescentar a interface o campo lookup, só vou colocar para vocês verem o que acontece.

Falta-nos o último passo que é a criação do Fluxo de Trabalho sobre a entidade Lead:

A nota mais importante aqui é a checkbox “Executar este fluxo de trabalho em segundo plano”, pois ao desmarcarmos esta checkbox estamos a dizer que este Fluxo de Trabalho vai correr imediatamente.

Na configuração do Fluxo de Trabalho não há muito a fazer, por isso vamos avançar para a configuração dos passos, o primeiro passo a ser configurado é relacionar o registo que vamos criar com o registo da entidade CustomAutoNumber que está reservado para a Lead:

Na definição de propriedades vamos escolher automaticamente o registo da entidade CustomAutoNumber:

De seguida vamos querer incrementar o número do registo associado a Lead da entidade CustomAutoNumber:

Na definição de propriedades vamos dizer que queremos incrementar o campo numeracao:

Por fim vamos atualizar a Lead com a numeração:

Nas propriedades nada mais simples vai-se dizer que o campo da Lead que vai ficar com a numeração é a composição entre o prefixo e o número em que a entidade vai:

Para quem não está tão familiarizado com os Fluxos de Trabalho, neste caso temos que escolher o “Prefixo” e fazer “Adicionar” e “OK”, depois para colocarmos “-” escrevemos diretamente na caixa de texto e depois escolhemos o campo “numeração, fazemos novamente “Adicionar” e “OK”. Vejam aqui o resultado:

Como podem ver o campo do lookup está preenchido e a numeração incrementada. Missão cumprida :D

 

Até a próxima.

Tags: , ,

CRM 2013 SP1 - UR1

by Pedro Azevedo 28. September 2014 16:37

 

Boas pessoal,

Foi disponibilizado o UR1 do CRM 2013 SP1 (v6.1.1), tal como tinha avisado neste momento existem duas “frentes” no CRM 2013, para quem instalou o CRM 2013 SP1 e quem não instalou.

Este update é para quem tem o SP1, para quem não tem recentemente saiu o UR3. Este rollup pode-se transferir aqui. Para mais informações podem ver aqui, este rollup contém mais 94 issues resolvidos.

 

Até a próxima.

Tags: , , ,

CRM 2013 - Customizar caixa de pesquisa de um lookup

by Pedro Azevedo 16. September 2014 23:29

 Boas pessoal,

Neste post vou rever um dos artigos mais requisitados mas que foi escrito para a versão do CRM 2011. O tema é “Customizar caixa de pesquisa de um lookup”. Para complementar este posta aconselho a darem uma vista de olhos neste post também.

Antes de começarmos a pensar nisto aviso que este tipo de operação ainda não é suportado pela Microsoft, logo o código aqui presente pode não funcionar em todas as ocasiões. O código é muito semelhante ao que tínhamos no CRM 2011, só que a estrutura do HTML no CRM 2013 foi modificado por isso deixou de funcionar. Esta é a razão do código não ser suportado, a Microsoft pode alterar qualquer coisa e não se preocupa com os efeitos colaterais.

A mudança é muito simples temos que acrescentar o sufixo “_i”. Eu tive que acrescentar também código para esperar que este elemento seja selecionável, pois o elemento que persiste estas opções só aparece quando carregamos no controlo.

Vou colocar aqui o código corrido com todas as opções:

function changeType(){
	if (document.getElementById("customerid_i")) {
		//Dizer qual a entidade que aparece como defeito neste caso a entidade Contacto
		document.getElementById("parentcustomerid").setAttribute("defaulttype", "2");
		
		//Restringir quais as entidades que podemos selecionar neste caso a entidade Contacto
		document.getElementById("customerid_i").setAttribute("lookuptypes", "2");
		
		//Dizer quais as entidades, os nomes das entidades e os respectivos icons
		document.getElementById("customerid_i").setAttribute("lookuptypenames", "account:1,contact:2,lead:4");
		document.getElementById("customerid_i").setAttribute("lookuptypeIcons", "/_imgs/ico_16_2.gif:/_imgs/ico_16_4.gif:/_imgs/ico_16_8.gif");
		
		//Desabilitar a escolha de uma vista
		document.getElementById("customerid_i").setAttribute("disableViewPicker", "1");
	}
	else {
		setTimeout("changeType();", 1500);
	}
}

 

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