Histórico da Página
Informações Gerais
Especificação | |||
Produto |
| Framework |
|
Segmento Executor |
| ||
Projeto1 |
| PCREQ-10031 |
|
Requisito1 |
|
| |
País | (X) Brasil ( ) Argentina ( ) Mexico ( ) Chile ( ) Paraguai ( ) Equador ( ) USA ( ) Colombia ( ) Outro _____________. |
Objetivo
Criar um mecanismo para possibilitar que processos e relatórios possam ter sua execução agendada via protocolo http, adaptar a classe RMSProcess pra que seja possível enviar notificações ao Fluig e fazer a integração do novo Reports com o GED.
Com essa mudança, teremos os seguintes benefícios:
- Será possível agendar a execução de processos em apps criados com o THF (TOTVS HTML Framework).
- A execução de relatórios também será disponibilizada via THF.
- Qualquer aplicativo que suporte comunicação via HTTP e que construa mensagens no padrão definido pelo THF poderá agendar a execução de processo e relatórios do CorporeRM.
- Os relatórios produzidos pelo novo gerador poderão ser exportados diretamente para o GED.
- Poderá ser enviado notificações para o Fluig quando da execução de qualquer processo no CorporeRM.
Definição da Regra de Negócio
- Execução de processos
Para agendar a execução de algum processo, será necessário criar um controller WebAPI para disponibilizar um meio de acessar a funcionalidade via web. Esse controller deverá ser criado por cada segmento e deve ser um sub-tipo do controller RMSFrameHtmlController que está definido no assembly RM.WebAPI.dll. Como os parâmetros necessários para a execução do processo devem ser providos pelo controller, este deve receber no corpo da requisição um objeto do tipo RMSJobExecutorInfo<T>, onde T é algum sub-tipo de RMSJobParameter, e este deve conter propriedades que serão fonte de dados para os parâmetros do processo. O tipo RMSJobExecutorInfo<T> contém todas as propriedades comuns à todos os processos do CorporeRM bem como as informações utilizadas para o agendamento da execução.
Para agendar a execução do processo, deve-se utilizar uma instância de RMSJobSchedulerBase<T> onde T também é do tipo RMSJobParameter. Essa classe é responsável por fazer a carga dos parâmetros do processo e, logo após, realizar a leitura dos parâmetros comuns do processo na classe RMSJobexecutorInfo<T> e associá-los aos parâmetros de execução do processo. Esta classe também define o método virtual DoReadParamsProc que deve ser sobrescrito caso haja necessidade de passar parâmetros específicos do processo e/ou alterar parâmetros comuns. Para fazer o agendamento do processo deve ser realizada uma chamada ao método SubmitJob da classe que retornará um objeto do ripo RMSJobInfo que conterá as informações do job criado.
Abaixo encontra-se o modelo de um controller que agenda a execução de um processo que espera dois valores inteiros para sua execução:
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
/******************************************/ /** DEFINIÇÃO DO CONTROLLER **/ /******************************************/ [RoutePrefix("sales")] public class SampleController : RMSFrameHtmlController { // acessível em api/sales/executeprocess [HttpPost] [Route("executeprocess")] public RMSFrameHtmlResponse<RMSJobInfo> Execute([FromBody]RMSJobExecutionInfo<SampleParameters> p) { try { // cria uma instância do scheduller que agendará a execução do processo // e submete os parâmetros de execução do mesmo... RMSJobInfo result = new SampleScheduller().SubmitJob(p, this.Context); // monta a mensagem de retorno padrão do THF... return new RMSFrameHtmlResponse<RMSJobInfo> { Data = result, Length = 1 }; } catch (Exception ex) { // fazer o tratamento da exeção... throw ex; } } } /******************************************/ /** DEFINIÇÃO DO SCHEDULLER **/ /******************************************/ public class SampleScheduller : RMSJobSchedulerBase<SampleParameters> { // deve-se passar para a classe base os dados do processo que // será agendado: Nome da Action, Código do sistema, Nome do // Processo e Nome do Server. public SampleScheduller() : base("NomeActionProcesso", "CodigoSistema", "NomeProcesso", "NomeServerProcesso") { // construtor padrão... } // método sobrescrito para que os dois parâmetros específicos do processo // possam ser carregados... protected override void DoLoadParamsProc(SampleParameters paramsSample, RMSParamsProc paramsProc) { // faz o cast dos parâmetros do processo para o tipo específico do processo SampleParamsProc p = (SampleParamsProc) paramsProc; // inicializa o valor dos parâmetros específicos do processo com o valor // que veio na requisição HTTP... p.Parametro1 = paramsSample.P1; p.Parametro2 = paramsSample.P2; } } /******************************************/ /** DEFINIÇÃO DA CLASSE DE PARÂMETROS **/ /******************************************/ public class RptReportJobParameter : RMSJobParameter { //Parâmetro #1 do processo [JsonProperty(PropertyName = "p1", Required = Required.Always)] public int P1 { get; set; } //Parâmetro #2 do processo [JsonProperty(PropertyName = "p2", Required = Required.Always)] public int P2 { get; set; } } |
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
// função para fazer a chamada ao controller // que faz o agendamento do processo function RunSampleProcess() { // objeto que será enviado na requisição... // este objeto corresponde à classe RMSJobSchedulerBase<SampleParameters> var scheduleParams = { "notify": true, "notifyEmail": false, "notifyEmailListschedule": "", { "pathtype": "TODAY", "filenametime": "10:00", "scheduledate": {"01/01/2016", }, "typeparameters": "TODAY",{ "timep1":"10:00" 98, "datep2": "01/01/2016"1, }, "parameterscodUsuario": {"mestre" } "p1": 98,}; // faz a "p2": 1, "codUsuario": "mestre" } }; // faz a requisição post...requisição post... $http.post('/api/sales/executeprocess', scheduleParams, []) .then(successCallback, errorCallback); } |
Por exemplo, se um processo necessita que seja informado dois inteiros em para sua execução, o controller deverá fornecer esse valor |||||||||||||||||||Todos os relatórios e processos poderão ter sua execução agendada por outras plataformasTodos os produtos possuem o seu respectivo ActionModuleController e nele possui dois métodos sobrescritos (GetModuleMenu e GetProfileMenu) utilizados para retornar a ribbon winforms (com itens a serem apresentados na MDI .NET) e a ribbon profile (com os itens de menu que serão visualizados no portal).
Até agora existiam duas estratégias adotadas pelo produto para inserir itens que não serão visualizados na ribbon porém necessitam de permissão (ou seja, devem ser carregadas na treeView de segurança no cadastro de perfil), são elas
- Inserir esses itens na ribbon profile
- Inserir esses itens na ribbon winforms e setar como visible false para que não sejam apresentados na nova MDI
Dessa forma a Lib fazia o merge dos itens de customização, gestão e ambiente na ribbon do produto e apresentava em winforms e na treeView de segurança no cadastro de perfil.
A partir de agora os métodos GetModuleMenu e GetProfileMenu estão como obsoletos e serão removidos nas próximas versões (ainda a definir), para isso é necessário que os produtos se adequem da seguinte forma:
- Implemente uma classe que herde de RMSMenuController, defina os itens conforme necessidade (Pages,Groups,Itens e suas respectivas Policies).
- No modelo antigo tínhamos o xxxActionModuleController (com as policies) e xxxRibbonControl (com os itens de menu) e a ligação entre os itens de menu e suas policies é feita pela tag de segurança, neste novo modelo está tudo dentro do controller.
- No modelo antigo tínhamos o xxxActionModuleController (com as policies) e xxxRibbonControl (com os itens de menu) e a ligação entre os itens de menu e suas policies é feita pela tag de segurança, neste novo modelo está tudo dentro do controller.
- Inserir esse controller na GMENU definindo a coluna MENUTYPE com os valores: 0 = winforms, 1 = Web, 2 = Profile.
Foram criadas 3 propriedades na RMSActionModuleController (que é o ancestral que o produto usa para implementação da Ribbon), são elas:
- ServerControllerName = Nome do controller que representa a ribbon winforms.
- ServerWebControllerName = Nome do controller que representa a ribbon web.
- ServerProfileControllerName = Nome do controller que representa os itens que não pertencem a nenhuma ribbon, porém são itens que necessitam de permissão. Este item está separado para que tenhamos um modelo mais coerente, porém caso o produto utilize o modelo de inserir itens no controller winforms como visible false irá funcionar, porém não é o recomendado pela lib, pois vemos segregar a responsabilidade dos controllers.
- Setar a classe xxxActionModuleController com as novas propriedades.
1) Comportamento da aplicação Winforms
Irá buscar o controller setado na propriedade ServerControllerName e criar uma Ribbon com esses itens + customização, Gestão e Ambiente, lembrando que neste caso o método GetModuleMenu nem será chamado por framework.
2) Comportamento da aplicação Web (Portal)
Irá buscar todos os controllers inseridos na GMENU com o MenuType = 1, com esses menus em memória irá buscar se existe alguma customização dos itens de menu web na tabela GMENUCUSTOM e realizar as devidas adequações no menu, somente após isso entregar para o portal os itens de menu. O menu.xml é completamente ignorado por framework.
3) Comportamento da funcionalidade de gerenciamento de permissões (Perfil)
Irá buscar os 3 controllers e montar a treeView de permissões no perfil, vale ressaltar que a treeview não é montada com os itens que possuem tag de segurança 0 (zero) ou "null"; caso um agrupador esteja com 0 (zero) ou "null" ele e seus filhos não serão apresentados.
4) Como customizar os itens de menu do portal
Esse item será utilizado para customizar o menu do portal, essa customização será utilizada pela fábrica e/ou pelo cliente. Antes era feita diretamente no menu.xml, agora temos um tela onde é permitido realizar a manipulação desses itens com as seguintes regras:
- Para itens padrões do sistema só é permitido habilitar/desabilitar
- Para itens novos é permitido inserir e colocá-lo em qualquer posição.
- Portando um item padrão que eu queira alterar o título, por exemplo, é necessário desabilitar o mesmo e criar um item customizado com a mesma action.
A funcionalidade está disponível em Gestão de Conteúdos/Cadastros/Menu Portal.
5) Foi criado uma parâmetro para ligar/desligar o menu server.
ENABLEMENUSERVER (Default false) e a partir da versão 12.1.12 o Default será true.
Tabelas Utilizadas
- Tabela que armazena os menus do RM, a coluna "MenuType " indica se o item é winforms, web ou profile.
Customização de itens de menu (somente para o Portal)
Defina se o item será Padrão ou Customizado:
Para o item Default só será permitido alterar a visibilidade do mesmo:
Selecione o tipo do menu como Padrão, e selecione o item de menu desejado na TreeView conforme print abaixo.Para item customizado é permitido definir até a posição onde o mesmo será inserido.
- Selecione o Tipo de Menu como customizado, e selecione o item de menu pai na TreeView conforme print abaixo:
- Esse item será inserido conforme definição acima.
- Gerenciador de Jobs (Web)
Existe também uma página HTML desenvolvida com o THF em que são exibidos todos os processos os processos (jobs) executados. Nesta página o usuário poderá visualizar e remover processos da fila de execução do RM. Não é possível fazer qualquer tipo de edição ou incluir processos na fila através dessa página.
Expandir |
---|
- Executar um relatório
Como a execução de relatórios é feita por um processo, foi criado um controller especial para execução de relatórios no assemply RM.Rpt.webAPI.dll. Esse controller funciona da mesma forma que os demais específicos para agendamento de processos. Entretanto, não é necessário que seja feito um controller e um scheduller para cada relatório, pois o modo de execução e a estrutura de parâmetros é o mesmo para todos os relatórios. Então basta que seja feita uma requisição POST para o endereço /rm/api/report/execute passando no corpo da requisição um objeto json do tipo RMSJobExecutionInfo<RptReportJobParameter>. Nesse objeto serão informados a coligada, o id, os filtros e parâmetros do relatório, bem como os demais valores referentes ao agendamento da execução do relatório. Os parâmetros referentes ao relatórios são definidos pela classe RptReportJobParameter.
Nesse mesmo controller também está disponível um método para recuperar as informações de metadados dos relatórios. Dentre as informações retornadas destacam as seguintes: Nome de todas as bandas do relatório, lista de todos os parâmetros, indentificador de filtro principal, nome de todas as tabelas e campos disponíveis, etc. O objeto retornado é definido pela classe RptReportInfo.
Abaixo encontra-se o código javascript para a execução de um relatório fictício que possui um parâmetro e é passado um filtro para a banda principal e outro para buscar as informações de metadados desse mesmo relatório..
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function execute (callback) {
var url = APP_BASE_SERVICES_URL + 'api/report/execute';
var parameters = {
"notify": true,
"schedule": {
"type": "TODAY",
"date": "2016-05-12T20:57:54.617Z",
"time": "18:05",
},
"parameters": {
"codColigada": 1,
"id": 198,
"parameters": [
{
"name": "CODTMV",
"value": 532
}
],
"filters": [
{
"bandName": "RptBand1",
"value": "TMOV.CODCOLIGADA = 1 AND TMOV.CODFILIAL = 2"
}
],
"codUsuario": "mestre"
}
};
$http.post(url, parameters, []).then(function (result) {
if (callback)
callback(result);
});
} |
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function info (callback) {
var url = APP_BASE_SERVICES_URL + 'api/report/info';
var parameters = { "codColigada" : 1, "id": 1, "codUsuario": "mestre" };
$http.get(url, parameters, []).then(function (result) {
if (callback)
callback(result);
});
} |
Schema dos objetos
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RMSJobInfo {
id (integer, optional),
execId (integer, optional),
children (Array[RMSJobInfo], optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RMSJobExecutionInfo[RptReportJobParameter] {
notify (boolean, optional),
notifyEmail (boolean, optional),
notifyEmailList (string, optional),
path (string, optional),
filename (string, optional),
schedule (RMSJobScheduleInfo, optional),
parameters (RptReportJobParameter, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RMSJobScheduleInfo {
type (string, optional),
date (string, optional),
time (string, optional),
repeat (boolean, optional),
repeatType (string, optional),
repeatTime (string, optional),
repeatCycle (integer, optional),
repeatFinish (string, optional),
repeatFinishDate (string, optional),
repeatWeekDays (RMSJobRepeatWeek, optional),
repeatMonthDay (RMSJobRepeatMonth, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptReportJobParameter {
codColigada (integer, optional): Código da coligada. ,
id (integer, optional): Identificador do relatório. ,
parameters (Array[RptReportParameter], optional): Parâmetros do relatôrio. ,
filters (Array[RptReportFilter], optional): Parâmetros do relatôrio. ,
codUsuario (string, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RMSJobRepeatWeek {
sunday (boolean, optional),
monday (boolean, optional),
tuesday (boolean, optional),
wednesday (boolean, optional),
thursday (boolean, optional),
friday (boolean, optional),
saturday (boolean, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RMSJobRepeatMonth {
day (integer, optional),
last (boolean, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptReportParameter {
name (string, optional): Parameter name. ,
value (Object, optional): Parameter value.
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptReportFilter {
bandName (string, optional): Parameter name. ,
mainFilter (boolean, optional): Informs if filter is the main one. ,
value (string, optional): Parameter value.
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptReportInfo {
parametersReport (Array[RptParameterReportPar], optional),
parametersProvider (Array[RptParameterProviderPar], optional),
filtersReport (Array[RptFilterReportPar], optional),
filtersFormulas (Array[RptFilterFormulaPar], optional),
dataSourceSchema (Object, optional),
memberInfo (RptMemberInfo, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptParameterReportPar {
visible (boolean, optional),
description (string, optional),
paramName (string, optional),
type (string, optional),
value (Object, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptParameterProviderPar {
paramName (string, optional),
value (Object, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptFilterReportPar {
mainFilter (boolean, optional),
bandName (string, optional),
value (string, optional),
filtersByTable (Array[RptFilterByTablePar], optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptFilterFormulaPar {
formulaName (string, optional),
value (string, optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptMemberInfo {
dataMember (string, optional),
fieldsInMember (Array[string], optional),
fieldsDBInMember (Array[string], optional),
fieldsOutMember (Array[string], optional),
columnsTableInMember (Array[string], optional),
bandName (string, optional),
childMembers (Array[RptMemberInfo], optional)
} |
Bloco de código | ||||||
---|---|---|---|---|---|---|
| ||||||
RptFilterByTablePar {
tableName (string, optional),
filter (string, optional)
} |
Este documento é material de especificação dos requisitos de inovação, trata-se de conteúdo extremamente técnico. |
---|