Partilhar via


Gestão do ciclo de vida das aplicações para análise de personalizações do modelo de dados

Aplica-se ao: Dynamics 365 Customer Service

Este artigo fornece informações aprofundadas sobre a gestão do ciclo de vida das aplicações (ALM) para relatórios personalizados baseados em personalizações do modelo de dados do Omnicanal para Dynamics 365 Customer Service.

Descrição Geral do ALM

O ALM é um passo importante quando pretende mover as alterações que são necessárias para relatórios personalizados entre ambientes, mas também pretende envolvimento manual mínimo. O ALM corretamente configurado pode ajudar a reduzir os erros manuais e poupar tempo.

Para personalização de relatórios, considere o ALM para a implementação de relatórios do Power BI. Pode conseguir esta implementação de diferentes maneiras:

  • Pode mover relatórios do Power BI entre ambientes usando pipelines de implementação do Power BI. Como alternativa, pode implementar relatórios do Power BI manualmente ao apontar para origens de dados corretas.
  • Uma vez que o centro de administração do Customer Service é uma aplicação condicionada por modelo, pode incorporar relatórios personalizados nela.

O ALM para Dynamics 365 envolve a configuração de relatórios no centro de administração do Customer Service.

O diagrama seguinte ilustra os passos. As caixas em azul que contêm texto branco representam tarefas que faz no Dynamics 365. As caixas em amarelo que contêm texto preto representam tarefas que faz no Power BI.

Diagrama que mostra os passos do ALM.

Migrar o relatório de configuração

Os relatórios que são adicionados ao Dynamics 365 são armazenados em entidades do Dataverse.

As entidades/tabelas seguintes são utilizadas para armazenar as informações de relatórios personalizados:

  • msdyn_dataanalyticsworkspaces tem as informações da área de trabalho que são configuradas durante a configuração inicial para análise do histórico/em tempo real.

  • msdyn_dataanalyticsreport armazena os relatórios personalizados que são adicionados ao mapa do site.

    • msdyn_reportid: o ID do relatório na área de trabalho do Power BI.
    • msdyn_dataanalyticsreportid: a chave primária no Dynamics 365.
    • msdyn_displayname: o nome a apresentar que aparece no relatório personalizado na aplicação condicionada por modelo Customer Service workspace.
    • msdyn_name: o nome do relatório na área de trabalho do Power BI.
    • msdyn_workspaceid: o ID da área de trabalho do Power BI que foi configurada no passo anterior.
    • msdyn_datainsightsandanalyticsfeatureid: f2266eb4-226f-4cf1-b422-89c5f48b40cb é o ID da caraterística para o histórico e 09c168be-efe2-4f08-a986-3aab7095c863 é o ID da caraterística para a personalização do modelo de dados em tempo real.

Para migrar os relatórios que são adicionados ao mapa do site, tem de mover os dados das entidades/tabelas. Pode usar a ferramenta de Migração da Configuração para este propósito. Este artigo fornece um ficheiro de esquema de amostra. Mais informações em Mover dados de configuração entre ambientes e organizações com a ferramenta de Migração da Configuração.

Após a migração, tem de atualizar as referências do relatório. Por outras palavras, tem de atualizar a área de trabalho do Power BI onde o relatório está alojado e o ID do relatório da área de trabalho. Este artigo fornece um script do PowerShell de amostra para referência e pode alcançar o mesmo resultado utilizando qualquer idioma.

Scripts de amostra

Esta secção inclui os seguintes scripts de amostra:

Ficheiro de esquema de amostra

O seguinte ficheiro de esquema XML consiste de relatórios personalizados que são criados e implementados na área de trabalho do Power BI. Pode utilizá-lo para exportar dados exportados pela ferramenta de Configuração da Migração. Mais informações em Mover dados de configuração entre ambientes e organizações com a ferramenta de Migração da Configuração e Criar um esquema para exportar dados de configuração.

<entities>
  <entity name="msdyn_dataanalyticsreport" displayname="Data Analytics Report" etc="10427" primaryidfield="msdyn_dataanalyticsreportid" primarynamefield="msdyn_name" disableplugins="false">
    <fields>
      <field displayname="Report Id" name="msdyn_reportid" type="string" customfield="true" />
      <field displayname="Data Analytics Report" name="msdyn_dataanalyticsreportid" type="guid" primaryKey="true" />
      <field displayname="Display name" name="msdyn_displayname" type="string" customfield="true" />
      <field displayname="Name" name="msdyn_name" type="string" customfield="true" />
      <field displayname="Report Display Order" name="msdyn_displayorder" type="number" customfield="true" />
      <field displayname="Report Provision Status" name="msdyn_provisionstatus" type="bool" customfield="true" />
      <field displayname="Report Page" name="msdyn_reportpage" type="string" customfield="true" />
      <field displayname="Report Group" name="msdyn_reportgroup" type="string" customfield="true" />
      <field displayname="Report Entity Name" name="msdyn_reportentityname" type="string" customfield="true" />
      <field displayname="Report Template Id" name="msdyn_reporttemplateid" type="string" customfield="true" />
      <field displayname="Dataset Id" name="msdyn_datasetid" type="string" customfield="true" />
      <field displayname="Is Enabled" name="msdyn_isenabled" type="bool" customfield="true" />
      <field displayname="Workspace Id" name="msdyn_workspaceid" type="string" customfield="true" />
      <field displayname="datainsightsandanalyticsfeatureId" name="msdyn_datainsightsandanalyticsfeatureid" type="entityreference" lookupType="msdyn_datainsightsandanalyticsfeature" customfield="true" />
      <field displayname="Analytics Checksum" name="msdyn_analyticschecksum" type="number" customfield="true" />
    </fields>
    <filter>&lt;filter type = 'and'&gt;
          &lt;condition attribute = 'msdyn_datainsightsandanalyticsfeatureid' operator = 'eq' value = '<<Feature ID of the model customization>> '/&gt;
          &lt;condition attribute = 'msdyn_displayname' operator = 'eq' value = '<<custom report name>>'/&gt; 
        &lt;/filter&gt;</filter>
  </entity>
</entities>

Use f2266eb4-226f-4cf1-b422-89c5f48b40cb como o ID da caraterística para o dados históricos e xxxx como o ID da caraterística para os dados em tempo real.

Script do PowerShell de amostra

O script seguinte utiliza o mecanismo de autenticação do segredo do ID de cliente. No entanto, pode utilizar qualquer tipo de autenticação modificando o script.

Este script liga-se ao Power BI através das APIs REST do Power BI. Liga-se ao Dataverse através de APIs Web do Dataverse.

#Get Power BI access token
function Get-PBIAccessToken {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        $TenantId,
        [Parameter(Mandatory=$true)]
        $PBIAppId,
        [Parameter(Mandatory=$true)]
        $PBIClientSecret
    )

    $authority = "https://login.microsoftonline.com/$TenantId/oauth2/token"
    $resource = "https://analysis.windows.net/powerbi/api"
    $body = @{
        "grant_type" = "client_credentials"
        "client_id" = $PBIAppId
        "client_secret" = $PBIClientSecret
        "resource" = $resource
    }
    Write-Host "Retreiving PBI Access Token"
    $tokenResponse = Invoke-RestMethod -Method Post -Uri $authority -Body $body
    
    return $tokenResponse.access_token
}
#Get Dataverse access token
function Get-DVAccessToken{
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        $tenantId,
        [Parameter(Mandatory=$true)]
        $clientId,
        [Parameter(Mandatory=$true)]
        $clientSecret,
        [Parameter(Mandatory=$true)]
        $dataVerseURL
    )
    $oAuthTokenEndpoint = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"

    # OAuth Body Access Token Request
    $authBody = @{
        client_id = $clientId;
        client_secret = $ClientSecret;    
        scope = "$($dataVerseURL)/.default"    
        grant_type = 'client_credentials'
    }

    # Parameters for OAuth Access Token Request
    $authParams = @{
        URI = $oAuthTokenEndpoint
        Method = 'POST'
        ContentType = 'application/x-www-form-urlencoded'
        Body = $authBody
    }
    Write-Host "Retreiving CRM Access Token"
    # Get Access Token
    $authResponseObject = Invoke-RestMethod @authParams -ErrorAction Stop
    return $authResponseObject
}
function Get-DVWorkspaceId {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        $dvAuthResponseObject,
        [Parameter(Mandatory=$true)]
        $dataVerseURL
    )

    $getDataRequestUri = 'msdyn_dataanalyticsworkspaces?$top=5&$select=msdyn_workspaceid,msdyn_name&$filter=(msdyn_name ne ''Customer Service Managed Workspace'' and _msdyn_datainsightsandanalyticsfeatureid_value eq ''f2266eb4-226f-4cf1-b422-89c5f48b40cb'')'
    # Set up web API call parameters, including a header for the access token
    $getApiCallParams = @{
        URI = "$($dataVerseURL)/api/data/v9.1/$($getDataRequestUri)"
        Headers = @{
            "Authorization" = "$($dvAuthResponseObject.token_type) $($dvAuthResponseObject.access_token)"
            "Accept" = "application/json"
            "OData-MaxVersion" = "4.0"
            "OData-Version" = "4.0"
        }
        Method = 'GET'
    }
    Write-Host "Retreiving Dataverse DCCP Workspace Id"
    # Call API to Get Response
    $getApiResponseObject = Invoke-RestMethod @getApiCallParams -ErrorAction Stop

    return $getApiResponseObject.value[0].msdyn_workspaceid
}
function Get-DVDCCPReports {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        $dvAuthResponseObject,
        [Parameter(Mandatory=$true)]
        $workspaceId,
        [Parameter(Mandatory=$true)]
        $dataVerseURL
    )
    Write-Host "Retreiving DV DCCP Reports"
    $getDataRequestUri = 'msdyn_dataanalyticsreports?$select=msdyn_dataanalyticsreportid,msdyn_name,msdyn_workspaceid&$filter=(msdyn_workspaceid ne '''+$workspaceId+''' and _msdyn_datainsightsandanalyticsfeatureid_value eq ''f2266eb4-226f-4cf1-b422-89c5f48b40cb'')'
      # Set up web API call parameters, including a header for the access token
      $getApiCallParams = @{
          URI = "$($dataVerseURL)/api/data/v9.1/$($getDataRequestUri)"
          Headers = @{
              "Authorization" = "$($dvAuthResponseObject.token_type) $($dvAuthResponseObject.access_token)"
              "Accept" = "application/json"
              "OData-MaxVersion" = "4.0"
              "OData-Version" = "4.0"
          }
          Method = 'GET'
      }
      $getApiResponseObject = Invoke-RestMethod @getApiCallParams -ErrorAction Stop
      # Output
      $dvReports = $getApiResponseObject.value
    return $dvReports    
}

function Get-PBIReports {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        $accessToken,
        [Parameter(Mandatory=$true)]
        $workspaceId
    )
    Write-Host "Retreiving PBI Workspace Reports"
    $headers = @{
        "Authorization" = "Bearer $accessToken"
          'Content-Type' = 'application/json'
      }
    $uri = "https://api.powerbi.com/v1.0/myorg/groups/$workspaceId/reports"
    $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
    $pbiReports = $response.value
    return $pbiReports
    
}

function Update-DVReportReferences
{
      [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        $pbiAccessToken,
        [Parameter(Mandatory=$true)]
        $dvAuthResponseObject,
        [Parameter(Mandatory=$true)]
        $workspaceId,
        [Parameter(Mandatory=$true)]
        $dataVerseURL
    )
    
    $pbiReports = Get-PBIReports -accessToken $pbiAccessToken -workspaceId $workspaceId
    Write-Host $pbiReports.Count
    $dvReports = Get-DVDCCPReports -dvAuthResponseObject $dvAuthResponseObject -workspaceId $workspaceId -dataVerseURL $dataVerseURL
    Write-Host $dvReports.Count
    Write-Host "Updating DCCP report references"
    $pbiReports
    foreach ($item in $dvReports)
      {
          $item.msdyn_name          
          $report = $pbiReports.value | Where-Object {$_.name -eq $item.msdyn_name}
          if($report -ne $null)
          {
              
              Write-Host "Updating report reference for $($item.msdyn_name) with PBI $($report.id)"
              $dvReportId = $item.msdyn_dataanalyticsreportid
              $patchRequestUri = "msdyn_dataanalyticsreports($($dvReportId))"+'?$select=msdyn_workspaceid,msdyn_dataanalyticsreportid'
              $updateBody  = @{
                  'msdyn_workspaceid' = ''+$workspaceId+''
                  'msdyn_reportid' = ''+$report.id+''
              } | ConvertTo-Json
              # Set up web API call parameters, including a header for the access token
              $patchApiCallParams = @{
                  URI = "$($dataVerseURL)/api/data/v9.1/$($patchRequestUri)"
                  Headers = @{
                      "Authorization" = "$($dvAuthResponseObject.token_type) $($dvAuthResponseObject.access_token)"
                      "Accept" = "application/json"
                      "OData-MaxVersion" = "4.0"
                      "OData-Version" = "4.0"
                      "Content-Type" = "application/json; charset=utf-8"
                      "Prefer" = "return=representation"  # in order to return data
                      "If-Match" = "*" 
                  }
                  Method = 'PATCH'
                  Body = $updateBody
              }
              
              $patchApiResponseObject = Invoke-RestMethod @patchApiCallParams -ErrorAction Stop   
          }
          else
          {
              Write-Host "Corresponding PBI report not found in PBI workspace with name $($item.msdyn_name)"
          }
      }
      return $pbiReports
}

###Sample usage########
#$PBIAppId = '<<Client ID which has access to Power BI workspace>>' 
#$TenantId = '<<Tenant Id of the DV/PBI organization>>'    
#$PBIClientSecret = "<<Secret of application user PBI>>" 
#$AppId = '<<Dataverse App id>>' 
#$ClientSecret = '<<DV client Secret>>' 
#$PowerPlatformEnvironmentUrl = "<<DV URL>>" 
#$PBIAccessToken = Get-PBIAccessToken -TenantId $TenantId -PBIAppId $PBIAppId -PBIClientSecret $PBIClientSecret
#$CRMAccessToken = Get-DVAccessToken -tenantId $TenantId -dataVerseURL $PowerPlatformEnvironmentUrl -clientId $AppId -clientSecret $ClientSecret
#$workspaceId = Get-DVWorkspaceId -dvAuthResponseObject $CRMAccessToken -dataVerseURL $PowerPlatformEnvironmentUrl
#Update-DVReportReferences -pbiAccessToken $PBIAccessToken -dvAuthResponseObject $CRMAccessToken -workspaceId $workspaceId -dataVerseURL $PowerPlatformEnvironmentUrl 

Pipeline YAML do Azure DevOps de Amostra

# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml
trigger:
- main
pool:
  vmImage: windows-latest
steps:
- task: CopyFiles@2
  inputs:
    Contents: '**'
    TargetFolder: '$(Build.ArtifactStagingDirectory)'
    CleanTargetFolder: true
    ignoreMakeDirErrors: true
  displayName: 'Copy files from Repo'
- task: PowerPlatformToolInstaller@2
  inputs:
    DefaultVersion: true
- task: PowerPlatformExportData@2
  inputs:
    authenticationType: 'PowerPlatformSPN'
    PowerPlatformSPN: 'Optimize25CRM'
    Environment: '$(BuildTools.EnvironmentUrl)'
    SchemaFile: '$(Build.ArtifactStagingDirectory)\source\Optimize25Schema\schema_sample.xml'
    DataFile: 'data.zip'
  displayName: 'Export reports sitemap data from Source'
- task: PowerPlatformImportData@2
  inputs:
    authenticationType: 'PowerPlatformSPN'
    PowerPlatformSPN: 'Optimize25POC'
    Environment: '$(BuildTools.EnvironmentUrl)'
    DataFile: 'data.zip'
  displayName: 'Import reports sitemap data to Target' 
- task: PowerShell@2  
  inputs:
    targetType: 'inline'
    script: |
      $ScriptContent = Get-Content "$(Build.ArtifactStagingDirectory)\source\automation\PipelineScript.ps1" -Raw
      Invoke-Expression $ScriptContent      
      # Write your PowerShell commands here.
      Write-Host "Assigning connection variables"   
      $PBIAppId = '$(PBIClientId)' 
      $PBIClientSecret = '$(PBIClientSecret)'
      $TenantId = '$(TenantId)'    
      $AppId = '$(CRMClientId)' 
      $ClientSecret = '$(CRMClientSecret)'  
      $PowerPlatformEnvironmentUrl = '$(GetConnectionVar.PowerPlatformEnvironmentUrl)' 
      $PBIAccessToken = Get-PBIAccessToken -TenantId $TenantId -PBIAppId $PBIAppId -PBIClientSecret $PBIClientSecret
      $CRMAccessToken = Get-DVAccessToken -tenantId $TenantId -dataVerseURL $PowerPlatformEnvironmentUrl -clientId $AppId -clientSecret $ClientSecret
      $featureId = 'f2266eb4-226f-4cf1-b422-89c5f48b40cb'      
      $workspaceId = Get-DVWorkspaceId -dvAuthResponseObject $CRMAccessToken -dataVerseURL $PowerPlatformEnvironmentUrl -featureId $featureId
      Write-Host $workspaceId
      Update-DVReportReferences -pbiAccessToken $PBIAccessToken -dvAuthResponseObject $CRMAccessToken -workspaceId $workspaceId -dataVerseURL $PowerPlatformEnvironmentUrl  -featureId $featureId

Os recursos seguintes podem ajudá-lo a obter mais informações sobre as capacidades de análise incorporadas do Omnicanal para Dynamics 365 Customer Service.

Próximo passo