Extensibilidade - Atributos de Utilizador
A extensibilidade tem como objetivo a personalização dos produtos Primavera para que estes se adaptem às necessidades específicas de cada negócio.
Os Atributos de Utilizador permitem ao utilizador estender o comportamento de uma entidade criando os seus próprios atributos, de modo a armazenar informação personalizada e relevante para o seu negócio.
Do ponto de vista técnico, um atributo de utilizador difere de um atributo modelado porque não é definido nem persistido através de uma coluna na tabela da entidade, mas através de JSON.
Arquitetura
Modelo de dados
Dado o aspeto dinâmico dos atributos de utilizador, o modelo de dados para a extensibilidade assenta essencialmente sobre a tecnologia JSON que garante a flexibilidade necessária.
Este modelo separa-se em duas partes, nomeadamente, a parte com os dados para definição dos atributos de utilizador, e outra, com os dados que correspondem aos seus valores.
Dados para definição dos atributos de utilizador
No que diz respeito à definição dos atributos de utilizador, foram alteradas as entidades SchemaEntity e SchemaAttribute já existentes na framework de modo a suportar a extensibilidade pretendida.
Para este efeito, foi adicionado à entidade SchemaEntity, o campo AllowExtensibility para indicar quais as entidades que suportam extensibilidade e o campo JsonSchema para armazenar um meta-documento JSON de acordo com a especificação JSON Schema usado para validação dos atributos.

Figura 1: Alterações efetuadas à entidade SchemaEntity e exemplo de um meta-documento JSON Schema.
Foi ainda necessário adicionar à entidade SchemaAttribute o campo IsCustomAttribute para distinguir os atributos modelados dos atributos de utilizador, e o campo CustomAttributeDefinition para armazenar um documento JSON com os metadados que representam o atributo do utilizador.

Figura 2: Alterações efetuadas à entidade SchemaAttribute e exemplo do documento JSON que representa um atributo de utilizador.
Note que a representação de um atributo de utilizador conta com propriedades comuns a todos estes (name, label, etc) mas também possui propriedades que variam consoante o tipo de dados (attributeTypeOptions e validationRules). Poderá consultar uma descrição mais completa destas propriedades no tópico Resources.
Dados com valores dos atributos de utilizador
Em relação aos valores armazenados em atributos de utilizador, estes serão persistidos na coluna CustomAttributes das entidades e validados recorrendo ao meta-documento referido no ponto anterior.
Dado que a extensibilidade é opcional para as entidades, esta coluna não é modelada mas sim gerada caso seja indicado na modelação que a entidade suporta extensibilidade.
A figura abaixo exemplifica as alterações efetuadas à tabela de uma entidade marcada como extensível, bem como um exemplo de um documento JSON com os valores dos atributos de utilizador.

Figura 3: Alterações efetuadas à tabela da entidade Order e exemplo de valores de atributos de utilizador.
Com o suporte de atributos de utilizador para tipos mais complexos, i.e: View, ValueList, Money, etc. O valor armazenado no campo CustomAttributes para esse atributo, não será um valor simples (como indica a figura acima) mas sim um valor complexo.
Exemplo valor armazenado para tipo View:
{"custom_Item":{"id":"aa22e71c-54a3-46cb-a492-d4053308aef2", "value":"PORTES","description":"Portes de Envio","baseEntityId":null}}
Exemplo valor armazenado para tipo ValueList:
{"custom_TipoItem":{"id":"5cd4844b-f1a9-41a4-8512-33390fa98ccf", "value":"1","valueDescription":"Item"}}
Exemplo valor armazenado para tipo Money:
{"custom_Currency":{"amount": 0, "fractionDigits":"2","symbol":"€"}}
Camada de backend
A camada de backend disponibiliza Web API's de produto e de integração que permitem toda a gestão dos atributos de utilizador bem como a interação com os mesmos no contexto das suas entidades.
As operações disponibilizadas por estas Web API's foram modeladas recorrendo à framework tirando partido dos mecanismos já existentes, tais como a persistência de entidades, mapeamentos de objetos e também do mecanismo para gestão e definição de permissões.
Web API's para gestão de atributos de utilizador
A lógica de negócio da gestão dos atributos de utilizador encontra-se concentrada na camada de extensibilidade representada na figura abaixo.

Figura 4: Camadas envolvidas nas Web API's de gestão de atributos de utilizador.
Como se pode constatar, a camada de extensibilidade interage com a camada de gestão das entidades e atributos, camada responsável pela persistência dos atributos de utilizador e dos atributos de sistema, e com a camada de gestão de view definitions, responsável por gerir as views definitions de extensibilidade e fundir as mesmas com as views definitions de sistema.
Web API's para interação de atributos de utilizador
A lógica de negócio da interação com os atributos de utilizador segue o mesmo fluxo que a interação com atributos de sistema e envolve as camadas representadas na figura abaixo.

Figura 5: Camadas envolvidas nas Web API's de interação com atributos de utilizador.
A camada de extensibilidade é aqui responsavel por efetuar as validações e a serialização dos documentos JSON que representam os valores dos atributoes de utilizador.
Poderá consular a secção Serviços para obter mais detalhes acerca de cada uma das operações suportadas.
Camada de frontend
A camada de frontend de extensibilidade é fornecida a partir do package npm @primavera/extensibility e faculta componentes para gestão e organização dos atributos de utilizador.
Gestão dos atributos de utilizador
A gestão de atributos de utilizador é realizada através de um modal ilustrado na figura abaixo que permite as operações de CRUD.

Figura 6: Componente UI para gestão de atributos de utilizador.
Como se pode constatar na figura acima, o modal apresenta uma entidade Master e as entidades Detail e Extension pertencentes ao contexto da entidade Master. Apenas as entidades que suportam extensibilidade são listadas.
O contexto supracitado é determinado a partir da ação de extensibilidade presente nas diversas vistas (Listas, Criação, Visualização e Edição) tal como apresentado na figura abaixo.

Figura 7: Ação de extensibildiade.
Esta ação é responsável por emitir um evento com informação do modulo e entidade em questão. Este evento é por sua vez capturado pelo componente de extensibilidade registado nas rotas das entidades que suportam extensibilidade o que permite despoletar a abertura do modal.
Modal Criação e Edição dos atributos de utilizador
O modal de criação/edição de um atributos de utilizador apresenta um conjunto de atributos comuns para os diversos tipos:
Figura 8: Modal de criação e edição de custom attributes
Os atributos gerais são os dados mínimos necessários para criar um atributo de utilizador - Label – titulo para a apresentação do novo campo na view - Name – é a chaves para o campo de utilizador, estes campos são sempre criados com o prefixo “custom_”. - Required – se o campo for obrigatório - Visible – se o campo for para estar visível no formulário - ReadOnly – se o campo é só de consulta (útil quando se tem um valor por default carregado por outro campo) - Type – a lista de tipos disponíveis para a criação de campos de utilizador (texto, decimal, entidade, dinheiro, etc.)
A secção dos valores por omissão permite configurar valores por default para o custom atribute, existem 3 opções: - Standard – de um valor ficho - Bind to other attribute – valor carregado via path e é sempre carregado um novo se os valores no path foram alterados - Other attribute first value - valor carregado via path e é preenchido apenas da primeira vez que o path tiver valores
A secção de ativar atributo para empresas tem como objetivo ativar determinado atributo apenas em determinadas empresas. por omissão está ativo para todas as empresas, mas pode se tirar essa tag e adicionar as empresas que se pretendam. Se a tag ‘ALL’ tiver nas selecionadas no momento da gravação as restantes vão ser descartadas e apenas gravada a ‘ALL’

O filtro da empresa só é possivel aplicar a entidades company dependent porque é a unica forma de nós conseguirmos saber em que empresa estamos a trabalhar, ou seja, em entidades como o ‘artigo’ este filtro não aparece e os atributos estão sempre disponíveis. Os atributos criados com filtro para a empresa apenas vão ser visiveis e estar ativos no contexto de empresas válidas isto é: - Na view da entidade só são apresentados os campos se a empresa fizer parte do filtro - Via API só é possivel enviar dados para estes campos nas empresas válidas, caso contrário é devolvido um erro.
Organização dos atributos de utilizador
A organização dos atributos de utilizador, em termos de ordem que aparecem nas vistas, é efetuada com recurso ao mecanismo de drag & drop no modal referido no ponto anterior. Por sua vez, esta ordenação visual tem impacto na ordem dos atributos constantes da view definition e consequemente são renderizados na ordem definida.
Adicionalmente, para as entidades do tipo Detail é possivel ainda sobrepor por operação a ordem definida dos atributos de utilizador, incluindo os de sistema, através do painel de configuração de detalhe representado abaixo. Esta redefinição de ordem é guardada na estrutura da view definition de extensibilidade.

Figura 9: Painel de configuração.
Note que a abertura deste painel segue a abordagem event subscriber tal como o modal supracitado.
Controlo de acesso
As funcionalidades de extensibilidade apenas são ativadas no produto de acordo com as seguintes condições:
- Presença da claim
claim_allow_extensibility_custom_attributesna subscrição; - O utilizador autenticado possuir um role com uma das permissões de extensibilidade.
Serviços
Por forma a possibilitar a gestão de atributos de utilizador foram modelados services, operations e resources.
Criação de atributos de utilizador
A resource ExtensibilitySchemaAttributeResource representa a definição de um atributo de utilizador e é apenas parcialmente modelada, sendo estendida em Primavera.Core.Patterns.Api.ExtensibilitySchemaAttributeResource para a definição de campos adicionais.
A operation AddCustomAttribute é responsável pela alteração dos seguintes elementos da aplicação:
- Atualizar a coluna
JsonSchemada tabelaCorePatterns.SchemaEntity, onde é armazenado o meta-documento Json Schema gerido com recurso à dependência Manatee.Json; - Adicionar um novo registo na tabela
CorePatterns.SchemaAttributescom base na resourceExtensibilitySchemaAttributeResource, que corresponde à definição do atributo de utilizador; - Adicionar uma nova view definition na tabela Azure correspondente, que representa uma view definition parcial apenas com os atributos de utilizador.

Figura 10: Service, operation e resource relacionados com a criação de um atributo de utilizador.
Atualização de atributos de utilizador
A operation UpdateCustomAttribute permite a atualização de um atributo de utilizador e é responsável pela alteração dos seguintes elementos da aplicação:
- Atualizar a coluna
JsonSchemada tabelaCorePatterns.SchemaEntity, onde é atualizado o meta-documento Json Schema gerido com recurso à dependência Manatee.Json; - Atualizar o registo na tabela
CorePatterns.SchemaAttributescom base na resourceExtensibilitySchemaAttributeResource; - Atualizar a view definition da extensibilidade na tabela Azure correspondente.

Figura 11: Service, operation e resource relacionados com a atualização de um atributo de utilizador.
Eliminação de atributos de utilizador
A operation DeleteCustomAttribute permite a eliminação de um atributo de utilizador e é responsável pela alteração dos seguintes elementos da aplicação:
- Atualizar a coluna JsonSchema da tabela
CorePatterns.SchemaEntity, onde é removido o atributo do meta-documento Json Schema gerido com recurso à dependência Manatee.Json; - Eliminar o registo na tabela CorePatterns.SchemaAttributes;
- Atualizar a view definition da extensibilidade na tabela Azure correspondente, de onde é removido atributo.

Figura 12: Service e operation relacionados com a eliminação de um atributo de utilizador.
Ativação/desativação de atributos de utilizador
A operation EnableCustomAttribute permite a ativação e desativação de um atributo de utilizador, através da utilização do parâmetro Enable e é responsável pela alteração dos seguintes elementos da aplicação:
- Atualizar a coluna
JsonSchemada tabelaCorePatterns.SchemaEntity, onde é atualizado o meta-documento Json Schema gerido com recurso à dependência Manatee.Json; - Atualizar a coluna
IsActiveda tabelaCorePatterns.SchemaAttributesparatrueoufalse, dependendo se o atributo está a ser ativado ou desativado, respetivamente; - Atualizar o documento JSON representativo do atributo, presente na coluna
CustomAttributeDefinitionda tabelaCorePatterns.SchemaAttributes, para refletir o novo estado (ativado / desativado); - Atualizar a view definition da extensibilidade na tabela Azure correspondente, onde é alterada a visibilidade do atributo.

Figura 13: Service e operation relacionados com a ativação/desativação de um atributo de utilizador.
Obter atributos de utilizador
A operation GetSchemaEntities é responsável por obter as entidades extensíveis relacionadas e os seus respetivos atributos de utilizador.
A resource ExtensibilitySchemaEntityResource representa uma entidade e a sua lista de atributos de utilizador.
Esta resource é apenas parcialmente modelada, sendo estendida em Primavera.Core.Patterns.Api.ExtensibilitySchemaEntityResource para a definição de campos adicionais.

Figura 13: Service, operation e resource relacionados com a obtenção de atributos de utilizador.
Editar a ordem de atributos de utilizador
A operation EditCustomAttributesOrder é responsável por alterar a ordem dos atributos de utilizador.
Por omissão, os atributos de utilizador são ordenados na vista pela ordem em que foram criados. Com esta operação o utilizador poderá reordenar os atributos de utilizador criados.

Figura 14: Service, operation e resource relacionados com a alteração da ordem de atributos de utilizador.
Verificar se o atributo de utilizador foi usado
A operation IsCustomAttributeUsed é responsável por verificar se o atributo de utilizador já possui valores armazenados.
Em caso afirmativo, o utilizador não poderá eliminar o atributo mas apenas desativá-lo.

Figura 15: Service e operation relacionados com a verificação do uso do atributo de utilizador.
Obter entidades por tipo de atributo de utilizador
A operation GetEntities é responsável para devolver entidades para serem usadas no componente TypeHead da gestão de atributos de utilizador.
Este serviço só é usado para atributos do tipo View (Entity Lookup) e ValueListItem (Enumerable).
Para o caso de um atributo do tipo View o serviço devolve entidades Master e Extension.
Para o caso de um atributo do tipo ValueListItem o serviço devolve entidades onde o entityType é tipo ValueList.
O serviço usa a resource EntityResource que é composto pela a NaturalKey e o Title das entidades retornadas.
O serviço suporta como parametros opcionais: DomainType - Representa o tipo do atributo e SearchTerm - Representa o filtro de pesquisa.
Exemplo no contexto de uma Order:
- Pedido de entidades para um um tipo de atribute View (app):
app/{tenantKey}/{orgKey}/corePatterns/schemaEntities/getEntities/Sales/Orders?domainType=View&searchTerm=
- Pedido de entidades para um um tipo de atribute ValueListItem (app):
app/{tenantKey}/{orgKey}/corePatterns/schemaEntities/getEntities/Sales/Orders?domainType=ValueListItem&searchTerm=
Figura 16: Service e operation relacionados com a obtenção de entidades por tipo de atributo de utilizador.
Atualização do valor do atributo de utilizador
A operation para atualizar um valor de um atributo de utilizador numa entidade é gerado através do uso dos TT's da solução Modeling (SDK).
Os TT's geram uma nova operação nos Services.Controllers.App e Services.Controllers.Api para as entidades que suportam extensibilidade.
-
Pedido de atualização de um atributo de utilizador (app):
app/{tenantKey}/{orgKey}/sales/quotations/{id}/customAttributes/{name}{name}- Nome do atributo de utilizador.
-
Pedido de atualização de um atributo de utilizador (api)
api/{tenantKey}/{orgKey}/sales/quotations/{companyKey}/{documentType}/{serie}/{seriesNumber}/{customAttributeName}{customAttributeName}- Nome do atributo de utilizador.
-
Exemplo de envio de valor do atributo de utilizador. O detalhe relativo ao resource usado deverá ver figura 18.
{"value":"Mandar ao cuidado do Sr. Alberto."}
Resources
A resource ExtensibilitySchemaAttributeResource é usada nas operations de criação, alteração e obtenção de atributos de utilizador, sendo constituída por:
Name- Nome do atributo;Label- Rótulo do atributo;IsRequired- Se é ou não obrigatório;IsVisible- Se é visível ou não;AttributeType- Tipo de atributo;ModifiedOn- Data e hora de modificação do atributo;IsActive- Se está ativo ou não;Id- Identificador doSchemaAttribute;SchemaEntityId- Identificador doSchemaEntitydo atributo;AttributeOptions-Dictionarykey e value referente a opções do tipo de atributo, onde a key é o tipo de propriedade e o value é o valor da propriedade;ValidationOptions-Dictionarykey e value referente a regras de validação, onde a key é o tipo de propriedade e o value é o valor da propriedade;DefaultValue- O valor por omissão do atributo.IsReadOnly- Se é readOnly ou não.

Figura 16: Resource ExtensibilitySchemaAttributeResource.
A resource ExtensibilitySchemaEntityResource é usada na operation de obtenção de atributos de utilizador, sendo constituída por:
Id- Identificador doSchemaEntity;Title- Título da entidade;Key- Key da entidade;ModuleName- Nome do módulo;IsComposition- Indica se a entidade é de composição ou não;Attributes- Lista de atributos.

Figura 17: Resource ExtensibilitySchemaEntityResource.
A resource ExtensibilityCustomAttributeValueResource é usada na operation de atualização do valor de um atributo de utilizador, sendo constituída por:
Value- Valor do atributo de utilizador.

Figura 18: Resource ExtensibilityCustomAttributeValueResource.
Motor de view definition
A view definition é uma estrutura de dados que define uma vista. Para dar suporte à extensibilidade, é criada uma view definition de extensibilidade aquando da criação de atributos de utilizador.
Localização da view definition
As view definitions encontram-se armazenadas na tabela CorePatterns.ExtensibilityViewDefinitions por Culture e por SchemaEntityId.
-
View definition de extensibiliade
A
keyda view definition de extensibilidade é definida pela conjugação do "módulo", "nome da entidade", a constante "extensibility" e "cultura".
Figura 19: Exemplo view definition de extensibilidade na tabela CorePatterns.ExtensibilityViewDefinitions.
-
View definition de sistema
As views definitions de sistema estão armazenadas em forma de ficheiros no cliente em \assets\view-definitions. A unica view definition base que não se encontra neste formato é a view definition base da custom entity onde é sempre gerada em runtime.
Estrutura
Para dar suporte à extensibilidade, e para uma melhor gestão, foi criada uma estrutura de classes que define uma view definition.
Abaixo encontra-se o diagrama das classes mais relevantes relativamente à view definition.

Figura 21: Estrutura de classes view definition.
O operationActions representa as acções, onde a acção de gestão de atributos de utilizador encontra-se nas configurationActions.
O fieldDefinition onde é representado como fields em JSON, representa os campos numa vista.

Figura 22: Estrutura da view definition em JSON.
Relativamente ao manuseamento da view definition de extensibilidade foi criada a estrutura de classes representada na figura abaixo.
A classe ExtensibilityViewDefinitionMetadata contém uma referência para a master e para o detail, onde o detail é um Dictionary, onde a key é o entity name e o value é referência à classe ExtensibilityDetailViewDefinition.
O campo GridLayoutDefinition do detail contêm o layout da grelha de detalhe, e é apenas populado aquando da ordenação de grelhas.

Figura 23: Fluxograma do motor rebuild da view definition.

Figura 24: Estrutura da view definition da extensibilidade em JSON.
Para dar suporte a algumas acções necessárias para a extensibilidade, foram adicionados novos campos na estrutura já existente.
-
FieldDefinitionTargetEntityName- Contém o entity name. (i.ePrimavera.Sales.Domain.QuotationLine);ExtensibilityConfiguration- Contém informação relativa ao createOperation, editOperation, claim e Id's das operações que têm acesso;IsCustomAttribute- Idenfica se o campo é um atributo de utilizador ou de sistema. Toma o valortruese for um campo de atributo de utilizador;AttributeTypeOptions- Contém as opções que variam mediante oAttributeType;Configuration- Dados relevantes para o caso específico deAttributeType=WebServiceTypeahead.
-
ConfigurationActionsClaimOperation- Claim para a operação de gestão de atributos de utilizador;AllowedOperationIds- Identificadores das operations que têm acesso à gestão de atributos de utilizador.
Visibilidade atributos utilizador
Os atributos de utilizador têm suporte para company dependent caso a entidade ao qual pertencem for company dependent. Com base na propriedade visibleExpression é alterado a visibilidade do campo de utilizador.
- Exemplo de visibilidade atribute utilizador master apenas para company
PRIMAVERA
"visibleExpression": "model && (model.company === 'PRIMAVERA')",
- Exemplo de visibilidade atribute utilizador detalhe apenas para company
PRIMAVERA
"visibleExpression": "parentModel && (parentModel.company === 'PRIMAVERA')",
Quando o atributo de utilizador é para ficar visivel para todas as empresas (o que acontece se pertencer a um atributo que não é company dependent), não existirá a propriedade visibleExpression no campo na view definition o que faz ser visivel para todos.
Merge
Para dar suporte à visualização dos atributos de utilizador numa vista, é efectuado um merge da view definition de sistema com a view definition de extensibilidade. A acção merge só é efectuada se a entidade suportar extensibilidade e se existir uma view definition de extensibilidade da entidade.

Figura 25: Fluxograma: Merge da view definition de sistema com a view definition de extensibilidade.

Figura 26: Fluxograma: Merge da view definition de sistema com a view definition de extensibilidade.
Rebuild da view definition
Na obtenção da view definition de extensibilidade, existe o suporte para rebuild da view definition no caso de ser detetada um problema de integridade da mesma.
A verificação da existência de atributos de utilizador da entidade é feita através da consulta do campo JsonSchema da tabela CorePatterns.SchemaEntity e o rebuild da view definition é efectuado através da consulta à tabela CorePatterns.SchemaAttributes para a entidade em que o atributo seja IsCustomAttribute = true.
O campo CustomAttributeDefinition contém toda a informação necessária para a reconstrução dos campos na view definition de extensibilidade, inclusive a ordem dos campos.

Figura 27: Fluxograma: Motor de rebuild da view definition.
Integridade de dados
Devido à persistência dos dados ser feita em formato JSON, não é possível utilizar os mesmos mecanismos de validação dos atributos modelados. Por forma a manter a consistência dos dados foram criados novos mecanismos de validação, descritos de seguida.
C# attributes
Por forma a garantir a integridade dos dados antes destes serem persistidos, foi criado o attribute Primavera.Core.Domain.ExtensibilityJsonSchemaValidationAttribute, que estende o atributo de sistema ValidationAttribute. Este atributo encontra-se associado à propriedade CustomAttributes das entidades, e é executado aquando da instanciação das mesmas.
Este atributo não contém qualquer lógica de validação, servindo apenas de ponte para o serviço de validação e normalização.
JSON schema
JSON Schema é uma especificação que permite a definição de meta-documentos com vista à validação de documentos JSON. A implementação concreta desta especificação utilizada no projeto é a fornecida pela biblioteca Manatee.Json.
Sempre que existe lugar à manipulação de valores de atributos do utilizador, e relembrando que a representação destes é um documento JSON, é executada uma validação com base no meta-documento existente na coluna JsonSchema da tabela SchemaEntities. Algumas das validações executadas são, por exemplo: validação de tipo (string, número, booleano, etc), valor numérico mínimo/máximo, limite mínimo/máximo de caracteres, número de casas decimais, padrão regex, etc.
Para uma lista completa de validações possíveis deve ser consultado o documento Json Schema Validation.
Serviço de validação e normalização
Por forma a agregar as tarefas de validação e normalização de valores relacionados com o contexto da extensiblidade, foi criado um serviço cuja interface reside em Primavera.Core.ApplicationServices.IExtensibilityService e implementação concreta em Primavera.Core.Patterns.Domain.DefaultExtensibilityService.
Este serviço fornece os métodos de validação possíveis com JSON Schema, bem como métodos personalizados para validações mais complexas.
O serviço possibilita ainda a normalização de valores de um formato ambíguo ou menos correto para um formato standard. Um exemplo recorrente é o caso das datas: a especificação JSON Schema requer que sigam o RFC3339 (secção 5.6), no entanto este nem sempre é o caso. Este serviço contém métodos que auxiliam na normalização de datas, boleanos, entre outros.
Outra funcionalidade importante fornecida por este serviço está relacionada com o preenchimento de valores por omissão (default values) de uma determinada entidade quando esta é instanciada. Existem dois pontos de entrada possíveis para esta funcionalidade: instanciação pela Entity Framework ou instanciação "normal" (vulgo new Object()); sendo ambas resolvidas neste serviço. A instanciação pela Entity Framework é interceptada recorrendo ao evento ObjectContext.ObjectMaterialized.
Modelação
A ativação da extensibilidade e gestão de permissões relacionadas é feita recorrendo à modelação. Todos os aspetos dos vários modelos estão descritos em seguida.
Modelo de entidades
O modelo de entidades é o responsável por indicar se uma determinada entidade suporta extensiblidade. Para tal, é necessário selecionar a opção "Allow Extensibility" nas propriedades das entidades pretendidas.

Figura 28: Ativar extensibilidade no modelo de entidades.
Modelo de apresentação
A localização dos atributos de utilizador de uma entidade master é, por omissão, o último "expander" da página da entidade no produto. É possível, no entanto, configurar esta localização no modelo de apresentação. Para tal, na view pretendida deve ser adicionada uma row configurada como:
Container Type = Expander
Content Type = Extensibility

Figura 29: Adicionar linha de extensibilidade - passo 1.

Figura 30: Adicionar linha de extensibilidade - passo 2.
Modelo de produto
Por forma a permitir uma determinada role fazer uso das funcionalidade da extensibilidade, é necessário recorrer ao modelo de produto e ativar a permissão "CorePatterns -> Extensibilities", acessível através do menu de contexto "Roles -> Select Role Permissions...".

Figura 31: Permissões de extensibilidade.
Codigo gerado
A ações demonstradas acima em Modelação têm os impactos descritos neste capítulo.
POCOs
As classes POCO que representam as entidades estendem originalmente as classes abstratas MasterBusinessEntityBase, DetailBusinessEntityBase e BusinessEntityExtensionBase do namespace Primavera.Core.Domain, no entanto estas classes não possuem nenhuma estrutura que permita a representação dos atributos de utilizador.
Porque as entidades extensíveis têm a necessidade de expor os atributos de utilizador, foram criadas as seguintes classes que incluem um dicionário representativo destes e dos valores associados: ExtensibleMasterBusinessEntityBase, ExtensibleDetailBusinessEntityBase e ExtensibleBusinessEntityExtensionBase. As entidades passam então a estender estas novas classes, que por sua vez estendem o seu equivalente original (descrito acima).
Resources
Pela mesma razão descrita no subcapítulo anterior, as resources originais não possuem nenhuma estrutura que permita a representação dos atributos de utilizador. Desta forma, e seguindo a mesma lógica, as classes originais MasterBusinessResourceBase, DetailBusinessResourceBase e BusinessResourceExtensionBase passam a ter equivalente na extensibilidade nas classes ExtensibleBusinessResourceExtensionBase, ExtensibleDetailBusinessResourceBase, ExtensibleMasterBusinessResourceBase; que implementam um dicionário representativo dos atributos de utilizador e dos seus valores.
Services
Quando uma entidade é marcada como extensível os serviços associados necessitam de efetuar validações adicionais devido ao facto dos atributos de utilizador serem representados através de um documento JSON ao invés de colunas na base de dados.
Desse modo, os serviços gerados têm a particularidade de fazer referência ao serviço de validação e normalização para executar as validações necessárias.
Mappers
Por forma a que o mapeamento entre resources relacionadas com entidades extensíveis também façam o mapeamento dos atributos de utilizador, os mappers gerados têm em consideração que o dicionário que os representa também deve ser copiado da origem para o destino do mapeamento.
View definition
Quando uma entidade é marcada como extensível (seja master, detail ou extension), é injetada na view definition da entidade master relacionada uma nova configuration action que permite o acesso ao modal de gestão dos atributos de utilizador. A figura abaixo mostra um exemplo desta configuration action.

Figura 32: Estrutura de dados da configuration action.
Adicionalmente, quando uma entidade master é marcada como extensível e indicada uma localização concreta para os atributos de utilizador, é injetado na view definition o seguinte placeholder que indica a localização onde a view definition da extensibilidade deve ser inserida aquando do processo de merge.

Figura 33: Placeholder de extensibilidade na view definition.
Fluxo de dados na persistência dos atributos de utilizador
Ao longo da criação ou edição de um documento que suporte extensibilidade, seja através do frontend ou da API de integração, os atributos de utilizador definidos para o documento são submetidos a um conjunto de operações antes da sua persistencia na base de dados. Estas operações correspodem a:
- normalização de valores;
- validação de valores;
- execução de side effects;
- carregamento de default values.
Estas operações estão implementadas e centralizadas no serviço ExtensibilityService que por sua vez delega a execução destas operações aos CustomAttributeHandlers associados ao tipos dos atributos em questão. A hierarquia de Handlers existente encontra-se ilustrada no diagrama abaixo.

Figura 34: Custom attribute handlers.
De seguida estão descritas as operações referidas anteriormente e o contexto em que são invocadas.
Normalização de valores
A persistência de valores de atributos de utilizador pode ser despoletada por diversas ações, nomeadamente: - Atualização do valor no draft de um documento; - Criação de um documento; - Atualização de um documento.
Transformação de valor
Dependendo da ação que despoletou a persistencia de atributos de utilizador e também do seu tipo, os valores destes últimos podem ser enviadas com estruturas de dados diferentes para o backend. Como tal, a normalização tem como objetivo transformar os valores dos atributos de utilizador num estrutura standard para que possa ser posterimente persistido em base de dados.
Filtro de atributos
É também nesta operação que é garantido que os atributos sejam tratados por forma a não serem alterados (readonly) ou até mesmo persitidos como é o caso dos atributos inativos.
Validação dos valores
A persistência de valores de atributos de utilizador nunca é realizada sem antes passar por uma operação de validação e é efetuado após a normalização dos valores. Esta validação é despoletada sempre que se crie ou atualize um documento através da anotação ExtensibilityJsonSchemaValidationAttribute utilizada na propriedade do POCO que representa a coluna onde são persistidos os valores dos atributos.
Anotação ExtensibilityJsonSchemaValidationAttribute
A anotação referida corresponde a uma classe que implementa a classe ValidationAttribute e recorre ao serviço ExtensibilityService para executar a operação de validação. É também nesta classe que é obtido, caso exista, a natural key da company de contexto por forma a validar o padrão company dependent.
Validação do padrão Company Dependent
O primeiro passo na execução da operação de validação é verificar, caso se trate de um documento que depende de empresa (company dependent), se os custom attributes enviados para persistencia estão associados a empresa de contexto, caso contrário é lançado um erro de validação (400 Bad Request).
Validação dos dados
De seguida, são validados os dados enviados para os atributos de utilizador recorrendo ao JsonSchema definido e associado a entidade correspondente ao documento em questão.
Side Effects
TODO
Default values
TODO