quinta-feira, 21 de março de 2019

Dynamics 365 - Update CRM via Portals

Sabemos que o Dyn365 Portals possui diversas limitações, e uma delas é a possibilidade de atualizar a base do CRM. Podemos apenas hoje usar a tecnologia Liquid para efetuar buscas no CRM.

Desta forma, segue um mecanismo para efetuar um CRUD no CRM, a partir do portal. O procedimento abaixo é um resumo do artigo criado pela UDS.

O exemplo abaixo faz uma atualização de status na tabela de apontamento.

1 - Criar a entidade PortalActions (escopo de organização), com os campos [new_action, new_parameters]
IMPORTANTE: Área de permissões do portal no Dyn365: Adicionar esta tabela no item [Permissões de Entidade], Escopo [Global], todos os privilégios, e no grid [Funções da Web], adicionar o [Administrador] e [Usuários Autenticados].

2 - Criar uma Page Template (chamada CustomActions) com o seguinte conteúdo Liquid:

{% assign action = request.params['action'] %}
{% assign parameters = request.params['parameters'] %}
{% fetchxml portalAction %}
<fetch>
 <entity name="new_portalactions">
 <attribute name="new_name" />
 <filter type="and">
 <condition attribute="new_action" operator="eq" value="{{action}}" />
 <condition attribute="new_parameters" operator="eq" value="{{parameters}}" />
 </filter>
 </entity>
</fetch>
{% endfetchxml %}

{% for item in portalAction.results.entities %}
<p>{{ item.new_name }}</p>
{% endfor %}


3 - Criar o seguinte Plugin (Message: RetrieveMultiple, EntityName: portalaction, Stage: pre)

public class ActionPlugin : IPlugin
{
    private IDictionary<string, Func<string, IOrganizationService, string>> _actionMap;

    public ActionPlugin()
    {
        _actionMap = new Dictionary<string, Func<string, IOrganizationService, string>>() {
        { "UpdateAppointmentStatus", UpdateAppointmentStatus }
     };
    }

    public void Execute(IServiceProvider serviceProvider)
    {
        var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
        var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        var service = serviceFactory.CreateOrganizationService(null);

        FetchExpression currentQuery = context.InputParameters["Query"] as FetchExpression;
        if (currentQuery != null) {
            XDocument parsedQuery = XDocument.Parse(currentQuery.Query);

            var requestParameters = parsedQuery.Descendants("filter").Elements().ToDictionary(e => e.Attribute("attribute").Value, e => e.Attribute("value").Value);

            if (requestParameters.ContainsKey("new_action") &&
            requestParameters.ContainsKey("new_parameters") &&
            _actionMap.ContainsKey(requestParameters["new_action"])) {
                string parameters = Encoding.UTF8.GetString(Convert.FromBase64String(requestParameters["new_parameters"]));
    parameters = parameters.Replace("\"", "");

                string result = _actionMap[requestParameters["new_action"]](parameters, service);
                var restulCollection = new EntityCollection();

    Guid id = Guid.NewGuid();
    restulCollection.Entities.Add(
    new Entity("new_portalactions") {
     Id = id,
     Attributes =
     {
      { "new_portalactionsid", id },
      { "new_result", result }
     }
    });
    
            }
        }
    }

    private string UpdateAppointmentStatus(string id, IOrganizationService service)
    {

        try {
            var _state = new SetStateRequest();
            _state.State = new OptionSetValue(1);
            _state.Status = new OptionSetValue(2);
            _state.EntityMoniker = new EntityReference("ENTITY_NAME", Guid.Parse(id));
            var stateSet = (SetStateResponse)crmService.Execute(_state);
        }
        catch (Exception ex) {
            return "Error: " + ex.Message;
        }

        return "Success";
    }
}

4 - Criar a classe JS [CrmActionHelper] e EXECUTÁ-LA em uma Portal Page (ONLOAD da página)

CrmActionHelper = CrmActionHelper || { __namespace: true };
(function (CrmActionHelperNamespace) {
 CrmActionHelperNamespace.Action = function (action, parameters) {
 var request;
 var url = "/CustomActions?action=" + action + "&parameters=" + prepareParameters(parameters);

 var $result = $.ajax({
 type: "GET",
 dataType : "json",
 url: url,
 beforeSend: function(xhr) {
 request = xhr;
 },
 error: function (jqXHR, textStatus, errorThrown) {
}

 });
 
 return { deferred: $result, request: request };
 }
 
 function prepareParameters(parameters) {
 return btoa(JSON.stringify(parameters));
 }
})(CrmActionHelper);
 
CrmActionHelper
 .Action("UpdateAppointmentStatus", "ID DO APONTAMENTO")
 .deferred
 .done (function (result) {
 });
 


That's it!