Limpar contactos ou contas de atividade marketing falhadas

by Pedro Azevedo 11. December 2014 11:10

Boas pessoal,

Fui deparado com um problema que apareceu no fórum do Dynamics CRM em português. O objetivo do desafio passava por ter uma maneira mais expedita para eliminar\desativar contas ou contactos que tenham dado erro aquando de uma distribuição de uma campanha.

O primeiro desafio foi obter estes erros. Na interface gráfica os erros aparecem no seletor “Falhas”. Então a minha primeira tentativa foi através da interface REST e sobre a entidade CampaignActivity (Atividades de Campanha) mas sem sucesso porque aqui não aparecem os erros.

 

Depois de ver melhor a imagem reparei que a vista se chama “Vista associada de falhas de operações em massa”. Logo fui estudar a entidade BulkOperation mas aqui mais uma vez só encontrei a atividade chamada “Distribuição de Email” e não as atividades geradas. Depois de ver todas as relações da entidade, cheguei a entidade BulkOperationLog esta sim tem todas as atividades que foram geradas, as que correram bem e as que deram erro. Como não existe muita informação sobre esta entidade, executei uma chamada para ver o esquema desta entidade:

Esta entidade tem um campo o ErrorNumber que se tiver valor diferente de 0 é porque esta atividade deu erro. Infelizmente só tem mesmo o número do erro e não tem qualquer descrição. Bem este foi outro desafio. Eu já tinha escrito um post sobre erros e explicado como chegar a descrição. Para já vai ficar com o número do erro mas é meu objetivo de criar algo para me dar também a descrição do erro.

Tendo então descoberto qual a entidade que tinha a informação que necessitava e para além do erro ainda possuí qual o cliente\contacto através do campo RegardingObjectId. Podem ver a pré-visualização do resultado final:

Para listar esta informação utilizei um plugin jQuery chamado jqGrid e usei esta versão, já que a versão que tinha utilizado até aqui passou a ter uma licença paga. Para aqui também já evoluí este componente do jqGrid para facilitar listar entidades do CRM, mais tarde vou escrever um post sobre este componente.

Falando mais concretamente da implementação a primeira coisa foi colocar um botão ao nível da atividade de campanha. Botão este que irá chamar um recurso web html, este botão foi criado mais uma vez com recurso a ferramenta Ribbon Workbench:

Este botão vai chamar uma função Javascript onde é passado qual a campanha que estamos a falar neste momento e com isso mostrar todas as atividades que falharam:

function openWebResource(campaignId) {
    var customParameters = encodeURIComponent("?campaignId=" + campaignId);
    Xrm.Utility.openWebResource("new_failedcampaign/failedcampaign.html", customParameters, 300,300);
}

Este recurso web tem o plugin jqGrid e a sua inicialização, o método fetchGridData vai ser responsável por ir obter as atividades com falha e preencher a tabela.

$("#jqGrid").jqGrid({
        datatype: "local",
        height: '100%',
        colModel: [ {label: 'Id Registo', name: 'ObjectId', hidden: true},
                    {label: 'Tipo Registo', name: 'TypeRegister', width: 90},
                    {label: 'Nome do Registo', name: 'NomeRegisto', width: 200},
                    {label: 'Erro', name: 'ErrorNumber', width: 140 }
        ],
        viewrecords: true, // show the current page, data rang and total records on the toolbar
        caption: 'Carregar Atividades de Campanha Falhadas',
        pager: "#jqGridPager",
        gridComplete: initGrid
    });

    fetchGridData();
});

function fetchGridData() {
    var campaignActivityId;
    if (location.search != "") {
        vals = decodeURIComponent(location.search).split("=");
        campaignActivityId = vals[2].toString().split(',');
    }

    var gridArrayData = [];
    var odataquery = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc";
    odataquery += "/CampaignActivitySet(guid'" + campaignActivityId + "')";
    odataquery += "?$expand=CampaignActivity_BulkOperations";
    odataquery += "&$select=CampaignActivity_BulkOperations/ActivityId";

    $.getJSON(odataquery, function(data) {
        if(data.d.CampaignActivity_BulkOperations) {
            var bulkOperations = data.d.CampaignActivity_BulkOperations.results;
            for (var idxBulkOper = 0; idxBulkOper < bulkOperations.length; ++idxBulkOper) {
                var activityId = bulkOperations[idxBulkOper].ActivityId;

                var odataquery2 = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc";
                odataquery2 += "/BulkOperationSet(guid'" + activityId + "')";
                odataquery2 += "?$expand=BulkOperation_logs";
                odataquery2 += "&$select=BulkOperation_logs/ErrorNumber,BulkOperation_logs/RegardingObjectId";

                $.getJSON(odataquery2, function(data) {
                    var bulkLogs = data.d.BulkOperation_logs.results;

                    for (var i = 0; i < bulkLogs.length; i++) {
                        gridArrayData.push({
                            ObjectId: bulkLogs[i].RegardingObjectId.Id,
                            TypeRegister: bulkLogs[i].RegardingObjectId.LogicalName,
                            NomeRegisto: bulkLogs[i].RegardingObjectId.Name,
                            ErrorNumber: bulkLogs[i].ErrorNumber
                        });
                    };

                    $("#jqGrid").jqGrid('setGridParam', { data: gridArrayData});
                    $("#jqGrid").trigger('reloadGrid');
                });
            }
        }
    });
}

Quero realçar o seguinte código:

var odataquery = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc";
odataquery += "/CampaignActivitySet(guid'" + campaignActivityId + "')";
odataquery += "?$expand=CampaignActivity_BulkOperations";
odataquery += "&$select=CampaignActivity_BulkOperations/ActivityId";

Este código vai obter todas as atividade de campanha e sobre cada uma obtenho os erros que aconteceram, como se pode ver a seguir:

var odataquery2 = Xrm.Page.context.getClientUrl() + "/XRMServices/2011/OrganizationData.svc";
odataquery2 += "/BulkOperationSet(guid'" + activityId + "')";
odataquery2 += "?$expand=BulkOperation_logs";
odataquery2 += "&$select=BulkOperation_logs/ErrorNumber,BulkOperation_logs/RegardingObjectId";

Sobre o plugin jqGrid usei a extensão Context Menu para poder realizar ações sobre os registos listados, entre eles o inativar e o apagar. Para inativar usei a mensagem SetStateRequest, vejam aqui a função que utilizei:

function SetStateRequest(active, entity) {
    var grid = $("#jqGrid");
    var rowKey = grid.getGridParam("selrow");
    var rowData = grid.getRowData(rowKey);
    var entityId = rowData.ObjectId;

    var state, status;
    if(active){
        state = 0;
        status = 1;
    }
    else{
        state = 1;
        status = 2;
    }

   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>" + entityId + "</a:Id>";
   requestMain += "              <a:LogicalName>" + entity + "</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(), true)
   // 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 () { SetStateResponse(req, successCallback, errorCallback); };
   req.send(requestMain);
}

Para apagar o registo usei a interface REST:

function DeleteEntity(accountId, entity) {
    var serverUrl = Xrm.Page.context.getClientUrl();
    var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc/" + entity + "Set";
    var ODataPath = serverUrl + ODATA_ENDPOINT;
    $.ajax({
        type: "POST",
        contentType: "application/json; charset=utf-8",
        datatype: "json",
        url: ODataPath + "(guid'" + accountId + "')",
        beforeSend: function (XMLHttpRequest) {
            XMLHttpRequest.setRequestHeader("Accept", "application/json");
            XMLHttpRequest.setRequestHeader("X-HTTP-Method", "DELETE");
        },
        error: function (xmlHttpRequest, textStatus, errorThrown) {
            alert("Status: " + textStatus + "; ErrorThrown: " + errorThrown);
        }
    });
} 

Reparem que para apagar temos que especificar o header “X-HTTP-Method” como delete.

Nesta solução a grande dificuldade foi mesmo a obtenção do tipo de erros referentes a esta comunicação o resto são coisas que já tínhamos visto anteriormente. Deixo-vos o ficheiro HTML do recurso web que usei, bem como a solução específica para o Dynamics CRM 2015. O meu objetivo é tornar esta solução num género de AddOn tanto para qualquer versão do CRM.

 

Até a próxima.

Tags: , , , , , , ,

Novos releases - CRM 2015

by Pedro Azevedo 26. September 2014 20:01

Boas pessoal,

Estas duas semanas têm sido repletas de novidades, tanto ao nível do Microsoft Dynamics CRM como na minha vida profissional.

Hoje vou falar do update denominado como CRM 2015. Para além disso saiu o UR1 para o SP1, o UR18 para o CRM 2011 e candidatei-me a MVP da Microsoft para a tecnologia Microsoft Dynamics CRM, mas cada um destes assuntos vai ter um post durante este fim-de-semana.

Este é um major release que estava denominado como “Vega” e está previsto para sair no final do ano. Já tínhamos visto um slide com as principais novidades do WPC 2014.

Para este post estou-me a basear essencialmente e mais uma vez no Release Preview lançado pela Microsoft. Este update baseia-se nos seguintes produtos:

  • Microsoft Dynamics CRM 2015 (on-premise será a versão 7.0)
  • Microsoft Dynamics CRM Online (2015 Update)
  • Microsoft Dynamics Marketing (2015 Update – Teremos que aplicar o update manualmente)
  • Microsoft Social Listening (2014 R2)

 

Microsoft Dynamics Marketing

Este update veio melhorar e muito este novo produto (que saiu com o major release anterior denominado como Leo), que para além da sua expansão para a Rússia e China, trouxe outras novidades:

Novo Editor de Emails

Um novo editor de email que possibilita criarmos um email através de templates ou de raiz, onde temos a hipótese de compormos o email através de drag and drop ou para utilizadores mais avançados utilizar um editor para HTML e CSS.

Consola de gestão de uma campanha

De modo a aumentar a confiança de quem faz marketing foram incluídos melhorias ao nível das condições múltiplas e a inclusão de testes A/B, que vai permitir uma maior confiança:

Integração com o Social Listening

A integração do social listening no Microsoft Dynamics Marketing, possibilitando a visualização do sentimento perante as campanhas realizadas:

 

Painel de colaboração com as vendas

A introdução de um painel de colaboração com as vendas, possibilita haver uma maior comunicação e maiores sinergias entre o Marketing e as Vendas, possibilitando as vendas de introduzir informações nas campanhas e poder aumentar os dados para o Marketing, bem como as vendas poderem registar-se em eventos que aconteçam em campanhas:

B2B Marketing

A capacidade de gestão de leads foi aumentada com integração de webinar, a capacidade de classificarmos a lead foi aumentada com a introdução de modelos múltiplos para a classificação das leads:

 

Gestão de recursos

A introdução de um calendário de Marketing vem possibilitar visualizar o plano e as suas principais metas e ter outra visão geral sobre o mesmo e com mais opções de colaboração com a integração com o Lync.

Automação de processos internos

Com um processo de aprovação e poder controlar o status de cada atividade e poder alinhar cada equipa com os objetivos delineados:

Vendas

Processos de vendas guiados

Os fluxos de processo de negócio foram melhorados, estes fluxos foi uma das novidades do CRM 2013. Resumidamente foi introduzida a capacidade de realizar branchs, basicamente e dependente de determinadas regras o fluxo de negócio pode escolher automaticamente entre dois caminhos, um dos exemplos dados é num processo de negócio de vendas, ter a mesma fase de qualificação mas dependente de ser um produto ou um serviço ter caminhos diferentes:

Família de produtos

Um dos objetivos desta versão é a melhoria na gestão dos produtos com a possibilidade de conseguirmos realizar bundles de produtos e podermos ter produtos ou acessórios recomendados, ou seja, numa cross-sell ou up-sell podermos ter produtos\acessórios que podemos vender nesse negócio, ou apresentar produtos como alternativas:

Hierarquia de vendas

Podermos visualizar como é que a informação está agrupada ou relacionada por uma visualização hierárquica dos dados. Esta visualização pode-se aplicar nas seguintes entidades: clientes, produtos ou utilizadores. Sobre cada tile podemos executar várias operações:

Por exemplo no exemplo acima estamos a ver uma hierarquia de um cliente, sobre um cliente podemos realizar as seguintes operações:

  • Visualizar como é que a receita esta distribuída;
  • Navegar para contas filha e saber onde estão os negócios;
  • Descobrir quem está a trabalhar num cliente e pedir ajudar de outros enviando email ou partilhando conta com outra pessoa;
  • Ver detalhes importantes sobre um cliente.

Isto tudo está disponível em mobile que vamos falar a seguir.

 

Melhorias na aplicação para tablets

A parte de vendas foi melhorada para aumentar a produtividade neste módulo, para além de podermos visualizar os dados hierárquicos, os dashboards podem ser habilitados para serem vistos no mobile e ter páginas de entrada personalizadas, mas para mim a grande melhoria tem a ver com cenários onde não estamos conectados a nossa organização, possibilitando com a criação de rascunhos de registos e haver uma sincronização quando estivermos ligados a nossa organização:

Módulo de serviço

Gestão de incidentes

No último update houve grandes melhorias neste módulo principalmente na gestão dos SLAs, entitlements e no novo controlo Time. Com esta versão temos a possibilidade de pausar e retomar o SLA e ter a noção de quanto tempo esteve em cada uma destas fases:

Microsoft Social Listening

Para além das fontes atuais (redes sociais – Facebook, Twitter, …), foram adicionadas fontes para sites de notícias, a análise do sentimento vai suportar a língua italiana.

 

Plataforma

Pesquisa

Uma das funcionalidades mais requisitas era haver uma pesquisa global, ou seja, até agora conseguíamos pesquisar registos de uma determinada entidade, com esta nova funcionalidade permite-se fazer uma pesquisa sobre todos os registos. Esta possibilidade até agora estava disponível através de um add-on. Esta funcionalidade está acessível na barra de navegação através de um novo icon de pesquisa avançada.

 

Sincronização de registos

Como sabemos a sincronização de registos pode ser feita entre o CRM e o Outlook\Exchange. Com esta nova versão podemos sincronizar mais informações:

·         Mais campos dos contactos e tarefas

·         Tarefas atribuídas

·         Anexos de compromissos

Outra novidade é ter visualmente quais os dados que foram sincronizados. Por falar no Outlook a configuração do CRM para o Outlook foi melhorado com um novo design.

 

Regras de Negócio

Outra das novidades que foi introduzido no CRM 2013 são as regras de negócio, possibilidade de validar dados sem que seja necessário escrever uma única linha de código. Neste update foram melhorados alguns pontos:

·         A execução destas regras do lado do servidor permite que estas sejam executadas independentemente de onde as mudanças são efetuadas no lado do cliente ou através do SDK. As regras são executadas na criação ou atualização de um registo. Ações no formulário (de visibilidade, habilitar e desabilitar e obrigatoriedade de campos) são ignoradas. Esta melhoria vem retirar muito do código de validação efetuada nos plugins.

·         O suporte a uma estrutura If…Else…If…Else… permite definir-nos estruturas mais complexas. Bem como agrupar múltiplas expressões através de blocos de condição And\Or.

·         Suporte a valores (quando se cria registos) e comportamentos por defeito.

O editor das regras de negócio foi melhorado para dar suporte as novidades acima.

 

Fluxos de Processos de Negócio

Agora passa a ser possível aceder a estes objetos através da API cliente, ou seja, através do Javascript. Poderá ser possível ativar e habilitar processos, bem como sermos notificados aquando da mudança de estágio.

 

Campos calculados

Um novo tipo de campo, onde podemos definir a fórmula e condições para poder efetuar um determinado cálculo. Isto tudo sem escrever uma única linha de código. As fórmulas podem referir campos da entidade em causa ou entidades relacionadas.

 

Campos rollup

Estes campos permitem que sejam recolhidos campos das entidades relacionadas (com uma relação de 1:N). Estes campos podem ser do tipo decimal, número, moeda e do tipo data. Este tipo de campo permite por exemplo saber o total de oportunidades que um cliente tem, somando as todas as oportunidades de contas filha.

Em resumo os valores são passados do filho para o registo pai. Existem algumas limitações, como a criação de 100 campos rollups por organização e 10 por cada entidade.

Os campos rollup são calculados por tarefas de sistema assíncronas. Estas tarefas correm regularmente conforme um padrão de recorrência, quando são criados ou atualizados correm numa tarefa diferente numa tarefa em massa. Estes campos são componentes da solução por isso são facilmente transportados para outros ambientes ou organizações.

 

Field Level Security

Este tipo de segurança estava apenas disponível para campos customizados, agora podemos habilitar este tipo de segurança para campos standard.

 

Conclusão

Para finalizar teremos que ter cuidado que com esta nova versão, versões mais antigas de tecnologias Microsoft vão deixar de ser suportadas, entre outras o Windows Server 2008, Windows Server 2008 R2, SQL Server 2008, SQL Server 2008 R2, e todas as versões do Windows Small Business Server, Internet Explorer 8 e Internet Explorer 9.

Os próximos updates conforme o roadmap mostrado no Convergence 2014 em Atalanta existirá mais dois updates este ano. Este updates são denominados por Hydra e Electra. Mas penso que mais novidades serão mostradas no Convergence 2014 em Barcelona.

 

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