V10 RecursosGuias
RecursosGuias
Guias
Voltar | Lista de artigos

Como implementar uma Smart Action do tipo Função de Extensibilidade?

Última alteração a 27/10/2026

É possível implementar uma Smart Action do tipo Função de Extensibilidade no ERP Primavera com o Visual Studio. Uma Smart Action de Extensibilidade permite injetar os seus próprios dados e prompt na chamada ao Pulse, bem como tratar a resposta do Pulse, tudo através da sua assembly de extensibilidade. Tem total controlo sobre o contexto enviado ao Pulse e o que acontece com o resultado.

Pré-Requisitos

  • ERP Primavera instalado.
  • Visual Studio e .NET Framework 4.7.
  • Ambiente de desenvolvimento configurado.

Passo 1: Criar Projeto

  1. Após abrir o Visual Studio, selecionar Ficheiro | Novo | Projeto;
  2. Na janela apresentada, na árvore à esquerda, escolher a linguagem C#;
  3. Selecionar o tipo de projeto Class Library (.NET Framework);
  4. Atribuir o nome CustomSmartAction ao projeto e clicar em OK.

Passo 2: Referências

Após criar o projeto, é necessário adicionar referências à plataforma de extensibilidade e aos módulos com que irá trabalhar:

•	Primavera.Extensibility.CustomSmartAction.dll
•	Primavera.Extensibility.Integration.dll
•	Primavera.Extensibility.BusinessEntities.dll
•	ErpBS100.dll
•	StdPlatBS100.dll

Passo 3: Criar Classe

  1. Renomear a classe de Class1.cs para SmartAction.cs;
  2. Adicionar os namespaces necessários no início do ficheiro com a diretiva using;
  3. A seguir ao nome da classe, adicionar Primavera.Extensibility.CustomSmartAction.CustomSmartAction. Este passo indica que a classe passa a herdar da classe base da API CustomSmartAction todos os métodos, propriedades e atributos, como por exemplo o PSO (acesso à plataforma) e o BSO (acesso aos módulos).
  4. Implementar os dois métodos de extensão obrigatórios (ver tabela abaixo);
  5. Compilar a solução em Build | Build Solution.
  6. Registar a assembly conforme descrito no artigo de apoio.

Métodos

MétodoQuando é chamadoFinalidade
BeforeExecution(string smartActionName, T businessEntity)Antes da chamada ao PulseConstrói e devolve o pedido: contextos e prompt
AfterExecution(string smartActionName, string result)Após a chamada ao PulseTrata o resultado gerado pelo Pulse

1. BeforeExecution

Deve utilizar o parâmetro smartActionName para encaminhar para a Smart Action correta e efetuar cast de businessEntity para o tipo de entidade de negócio (BE) esperado.

Devolva um CustomSmartActionRequest preenchido com:

  • Contexts — lista de CustomSmartActionContext, cada um com:
  • Background — descrição em texto simples dos dados fornecidos (ajuda o Pulse a interpretá-los).
  • Data — DataTable com as linhas de dados.
  • Prompt — a questão ou instrução enviada ao Pulse.
  • Files — opcional. Dictionary<string, byte[]> com o nome e o conteúdo binário dos ficheiros a enviar ao Pulse (ver secção Envio de Ficheiros).

Para nomes de Smart Action não reconhecidos, devolva new CustomSmartActionRequest()

2. AfterExecution

Recebe o nome da Smart Action e a resposta gerada pelo Pulse. Utilize este método para apresentar o resultado ao utilizador, escrever num campo, registar em log, ou desencadear qualquer lógica subsequente.

Exemplo

using Primavera.Extensibility.BusinessEntities.Data;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;

namespace MyCompany.Extensibility
{
    public class SmartAction : Primavera.Extensibility.CustomSmartAction.CustomSmartAction
    {
        public override CustomSmartActionRequest BeforeExecution(string smartActionName, T businessEntity)
        {
            if (smartActionName.Equals("Artigo", StringComparison.InvariantCultureIgnoreCase)
                && businessEntity is BasBE100.BasBEArtigo artigo)
            {
                var data = new DataTable();
                data.Columns.AddRange(new[]
                {
                    new DataColumn("Artigo"),
                    new DataColumn("Descricao"),
                    new DataColumn("Preco")
                });
                data.Rows.Add("A0001", "Item 1", "40.60");
                data.Rows.Add("A0002", "Item 2", "20.33");
                data.Rows.Add("A0003", "Item 3", "55.50");
                data.Rows.Add("A0004", "Item 4", "35.20");

                // Ficheiros só são enviados ao Pulse se a Smart Action tiver "Envio de Ficheiros" = Sim.
                var files = new Dictionary<string, byte[]>
                {
                    { "ficha-tecnica.pdf", File.ReadAllBytes(@"C:\Docs\ficha-tecnica.pdf") }
                };

                return new CustomSmartActionRequest()
                {
                    Contexts = new List()
                    {
                        new CustomSmartActionContext()
                        {
                            Background = "Lista de artigos com preços em euros.",
                            Data = data
                        }
                    },
                    Prompt = "Qual é o artigo mais caro e qual é o seu preço? Resuma também o conteúdo da ficha técnica anexada.",
                    Files = files
                };
            }

            if (smartActionName.Equals("DocumentoVenda", StringComparison.InvariantCultureIgnoreCase)
                && businessEntity is VndBE100.VndBEDocumentoVenda documentoVenda)
            {
                return new CustomSmartActionRequest()
                {
                    Contexts = new List()
                    {
                        new CustomSmartActionContext()
                        {
                            Background = "Documento de venda com dados do cliente, datas, totais e lista de artigos vendidos.",
                            Data = BuildSalesDocumentTable(documentoVenda)
                        }
                    },
                    Prompt = "Com base neste documento de venda, forneça uma análise do cliente, volume de vendas, descontos aplicados e valor final."
                };
            }

            return new CustomSmartActionRequest();
        }

        public override void AfterExecution(string smartActionName, string result)
        {
            this.PSO.MensagensDialogos.MostraAviso(
                "Resultado da Smart Action",
                StdBE100.StdBETipos.IconId.PRI_Informativo,
                result);
        }

        private DataTable BuildSalesDocumentTable(VndBE100.VndBEDocumentoVenda doc)
        {
            var dt = new DataTable();
            dt.Columns.AddRange(new[]
            {
                new DataColumn("TipoDoc"),        new DataColumn("Serie"),          new DataColumn("NumDoc"),
                new DataColumn("Cliente"),         new DataColumn("Data"),           new DataColumn("TotalMercadoria"),
                new DataColumn("TotalDesconto"),   new DataColumn("TotalIVA"),       new DataColumn("OutrosEncargos"),
                new DataColumn("TotalDocumento"),  new DataColumn("NumLinha"),       new DataColumn("Artigo"),
                new DataColumn("Descricao"),       new DataColumn("Quantidade"),     new DataColumn("PrecUnit"),
                new DataColumn("Desconto1"),       new DataColumn("Desconto2"),      new DataColumn("Desconto3")
            });

            int numLinha = 0;
            foreach (VndBE100.VndBELinhaDocumentoVenda linha in doc.Linhas)
            {
                numLinha++;
                dt.Rows.Add(
                    doc.Tipodoc, doc.Serie,
                    doc.NumDoc.ToString(CultureInfo.InvariantCulture),
                    doc.Entidade,
                    doc.DataDoc.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture),
                    doc.TotalMerc.ToString("0.00", CultureInfo.InvariantCulture),
                    doc.TotalDesc.ToString("0.00", CultureInfo.InvariantCulture),
                    doc.TotalIva.ToString("0.00", CultureInfo.InvariantCulture),
                    doc.TotalOutros.ToString("0.00", CultureInfo.InvariantCulture),
                    doc.TotalDocumento.ToString("0.00", CultureInfo.InvariantCulture),
                    numLinha.ToString(CultureInfo.InvariantCulture),
                    linha.Artigo, linha.Descricao,
                    linha.Quantidade.ToString("0.00", CultureInfo.InvariantCulture),
                    linha.PrecUnit.ToString("0.00", CultureInfo.InvariantCulture),
                    linha.Desconto1.ToString("0.00", CultureInfo.InvariantCulture),
                    linha.Desconto2.ToString("0.00", CultureInfo.InvariantCulture),
                    linha.Desconto3.ToString("0.00", CultureInfo.InvariantCulture)
                );
            }

            return dt;
        }
    }
}

Passo 4: Configurar Smart Action no ERP

Após implementar e registar a assembly de extensibilidade, crie a Smart Action diretamente a partir do formulário alvo:

  1. Abrir o formulário onde a Smart Action deve aparecer;
  2. Aceder à opção Smart Actions do formulário e criar uma Smart Action;
  3. Definir o tipo como Função de Extensibilidade;
  4. Definir o Nome com o valor que o método BeforeExecution verifica no parâmetro smartActionName (por exemplo: "Artigo", "DocumentoVenda").

Nota: o nome é a chave que encaminha a chamada para o bloco correto no método BeforeExecution — deve corresponder exatamente. A comparação deverá ser insensível a maiúsculas/minúsculas por convenção, conforme demonstrado no exemplo.

Envio de Ficheiros

Uma Smart Action do tipo Função de Extensibilidade também pode enviar ficheiros ao Pulse, através da propriedade Files do CustomSmartActionRequest.

  • Files é um Dictionary<string, byte[]=""> — a chave é o nome do ficheiro e o valor é o respetivo conteúdo binário.</string,>
  • No separador Geral da Smart Action existe a opção Envio de Ficheiros (S/N, por defeito N). Os ficheiros colocados em Files só são efetivamente enviados ao Pulse se esta opção estiver a Sim; se estiver a Não, qualquer conteúdo em Files é ignorado na execução.
  • A opção Envio de Ficheiros só pode estar ativa quando a Execução da Smart Action está definida como Não Necessita de Cálculos; fica desativada (e volta automaticamente a Não) quando a Execução é Necessita de Cálculos.
  • Ao contrário do tipo Queries — onde a plataforma pede os ficheiros ao utilizador antes de executar a Smart Action —, no tipo Função de Extensibilidade é sempre a própria extensibilidade que fornece os ficheiros em BeforeExecution; a extensibilidade é sempre invocada, independentemente do valor de Envio de Ficheiros.
  • Aplicam-se os mesmos limites do resto da plataforma: no máximo 5 ficheiros, cada um até 5 MB.

O caso Artigo no exemplo demonstra o preenchimento de Files.

Checklist

Preparamos a seguinte checklist com todos os passos necessários para auxiliá-lo neste processo:

  • Assembly de extensibilidade implementada e registada.
  • Classe herda de Extensibility.CustomSmartAction.CustomSmartAction.
  • BeforeExecution devolve um CustomSmartActionRequest preenchido para cada nome de Smart Action tratado.
  • AfterExecution trata o resultado do Pulse para cada nome de Smart Action.
  • Smart Action criada a partir do formulário alvo com o tipo Função de Extensibilidade e o nome correspondente.
  • Se a extensibilidade preenche Files em CustomSmartActionRequest, a opção Envio de Ficheiros da Smart Action está definida como Sim no separador Geral.
  • Um projeto base com exemplos de implementação está disponível no GitHub da Primavera.
Adicionar aos favoritos ou partilhar este artigo
Esta página foi útil?
Obrigado pelo seu voto.
Artigos Relacionados
Começar a Usar Como criar um projeto de integração com Visual Studio? Como criar um projeto de extensibilidade de interface (PEX) com Visual Studio? Como criar um projeto de extensibilidade de API (Motor) com Visual Studio? Como criar separadores do utilizador com Visual Studio?
Últimos Artigos Vistos
POSTMAN