O http://www.doens.be publicou este artigo e vou traduzi-lo aqui, é bastante útil!
Quando você quiser implementar sequências numéricas nos seus formulários no AX para por exemplo criar um ID sequencial, você só precisar implementar ‘numberSeqFormHandler‘.
Passo a passo:
Defina um objeto do tipo ‘NumberSeqFormHandler’ no ClassDeclaration do formulário:
1 2 3 4 | public class FormRun extends ObjectRun { NumberSeqFormHandler numberSeqFormHandler; } |
Crie um novo método no seu formulário que que instâncie seu objeto ou apenas retorne-o.
1 2 3 4 5 6 7 8 9 10 11 | NumberSeqFormHandler numberSeqFormHandler() { ; if (!numberSeqFormHandler) numberSeqFormHandler = NumberSeqFormHandler::newForm(TestParameters::numRefTEST().NumberSequence, element, TestTable_DS, fieldnum(TestTable,TEST) ); return numberSeqFormHandler; } |
Siga os passos abaixo adicionando as duas linhas no método create do datasource:
1 2 3 4 5 6 7 | public void create(boolean _append = false) { ; element.numberSeqFormHandler().formMethodDataSourceCreatePre(); super(_append); element.numberSeqFormHandler().formMethodDataSourceCreate(); } |
Agora no método delete do datasource:
1 2 3 4 5 6 | public void delete() { ; element.numberSeqFormHandler().formMethodDataSourceDelete(); super(); } |
Agora no método write, que é quando o usuário insere um novo registro ou atualiza:
1 2 3 4 5 6 7 8 | public void write() { ; ttsbegin; super(); element.numberSeqFormHandler().formMethodDataSourceWrite(); ttscommit; } |
Agora no validatewrite, que é quando um registro está para ser inserido ou atualizado:
1 2 3 4 5 6 7 8 | public boolean validateWrite() { boolean ret; ; ret = super(); ret = element.numberSeqFormHandler().formMethodDataSourceValidateWrite(ret) && ret; return ret; } |
Agora no linkactive que é quando o usuário seleciona um registro do datasource que está relacionado a outro registro de outro datasource.
1 2 3 4 5 6 | public void linkActive() { ; element.numberSeqFormHandler().formMethodDataSourceLinkActive(); super(); } |
E por último, no close, quando o formulário é fechado:
1 2 3 4 5 6 7 | public void close() { ; if (numberSeqFormHandler) numberSeqFormHandler.formMethodClose(); super(); } |
[]s
Pichler
Caros,
Hoje me deparei com um problema, após migrar um AX de 4 para 2009, alguns problemas de pós sincronização apareceram e por conta disso e quando foi resolvê-los direto no SQL eu recebi a mensagem: “See object explorer details for objects in this folder”. Até onde vi, o problema ocorre por usar o um sistema operacional de 32bits, onde a limitação de objetos é de 64k.
Enfim, para contornar o problema, basta pressionar F7 que os objetos são listados no “Object Explorer Details” e você consegue trabalhar, já para resolver o problema, eu não vou prosseguir porque ai é uma questão que o responsável pelos servidores deve se preocupar.
Obs.: Para exibir a quantidade de tabelas da database especifica, use a instrução: “SELECT COUNT(*) from information_schema.tables WHERE table_type = ‘base table’“.
[]s
Pichler
Caros,
Esse artigo foi originalmente publicado por VANYA KASHPERUK, em seu blog http://kashperuk.blogspot.com/ e apenas traduzido por mim.
No Dynamics AX 2009 a Microsoft introduziu um novo tipo de dados chamado UtcDateTime, que substituirá 2 tipos existentes, date e time, os quais ainda estão presentes.
Obviamente que a introdução destes dois novos tipos requer um tutorial sobre como eles podem ser usados nos formulários, como você pode filtrar campos com esse tipo de dados, como também quais funções estão disponíveis para serem usadas.
Então, eu fiz esse tutorial e espero que seja bastante útil para os desenvolvedores migrando para o AX 2009.
Faça o download do xpo usado no tutorial (SkyDrive)
O tutorial consistem em um único formulário que contem os seguintes elementos:
• uma grid, exibindo dados da CustTable;
• 4 botões para ações de filtro;
• 3 controles que permitirão especifica filtros condicionais para os dados.
No formulário você pode ver como os controles baseados no UtcDateTime são exibidos tanto em um grupo como também em um grid.
Abaixo uma explicação sobre a funcionalidade implementada, na forma de perguntas e repostas:
1.)
Q: Eu posso fazer um filtro no novo tipo UtcDateTime especificando apenas a Data?
R: Sim. Você simplesmente tem que especificar o valor da data quando for fazer o filtro, como abaixo. Note que isto também funciona quando você for fazer filtros pela interface normal (CTRL + F). qbdsCustTable.addRange(fieldNum(CustTable, CreatedDateTime)).value(queryValue(DateFilter.dateValue()));
O que é interessante é como o kernel processa este range. No infolog abaixo, você pode ver que o quando é visualizada na query, é exibido uma condição “==”, mas na realidade, como você pode ver no SQL Trace, um range condicional “>= && <=" é aplicado para varrer o dia inteiro. Perceba também, que os valores são exibidos no trace usando o TimeZone que eu estou, assim como o horário de verão.
2.)
Q: Eu posso filtrar usando apenas a hora?
R: Não, isto não é possível usando o UtcDateTime. O valor usado quando você especifica só a hora é o valor menor possível na combinação DateTime, ou seja, ‘1900-01-01 00:00:00′.
3.)
Q: Eu posso usar funções similares as anteriores em queries para o typo UtcDateTime?
R: Sim. Todas as principais funções existentes para trabalhar com QueryBuildRange também suportam o tipo UtcDateTime. Por exemplo, no infolog abaixo você pode ver como o range é aplicado nas duas UtcDateTime. Você também pode usar o método Global::QueryValue. Perceba que novamente o SQL converteu as datas para serem comparadas com as horas da minha localidade.
4.)
Q: Como o tipo de dados UtcDateTime é armazenado no Banco de Dados? É exibido da mesma forma que é exibido nos formulários?
R: Os campos UtcDateTime são sempre armazenados em UTC. Sempre que é exibido no formulário e ligado ao campo de uma tabela, os dados são convertidos para o tipo configurado nas preferencias do usuário. Nota, você precisa tomar cuidado com as conversões se o controle não estiver atrelado a um campo de uma tabela. Por exemplo, veja o método init() do tutorial.
5.)
Q: Quais funções estão presentes para trabalhar com o tipo de dado UtcDateTime?
R: A principal é a classe DateTimeUtil, ela permite adicionar dia/mês/ano, assim como aplicar um offset, pegar as preferências do usuário, converter de/para outros tipos e etc… Um exemplo pode ser visto abaixo:
1 2 3 4 5 6 | // getSystemDateTime() returns the current DateTime set in the system, not the current machine dateTime. // Note that getSystemDateTime() returns a UTC date and time, not your local date time. // In order to receive your local DateTime value, you should use methods applyTimeZoneOffset and specify the preferred time zone. utcDateTimeFilter.dateTimeValue(DateTimeUtil::applyTimeZoneOffset( DateTimeUtil::getSystemDateTime(), DateTimeUtil::getUserPreferredTimeZone())); |
6.)
Q: Isto significa que o suporte aos tipos Date e Time foram removidos?
R: Não, como mencionado anteriormente você pode usá-los.
7.)
Q: Eu não vejo o filtro atual no log do SQL no lugar eu vejo “?”. Como eu posso também limitar o número de dados/campos selecionados na base de dados?
R: Isto é apenas material extra, não relacionado a UtcDateTime, mas continua útil conhecer e prestar atenção!
CustTable tem um grande número de campos, e eu estou apenas exibindo 4 deles no formulário, então é ignorante eu retornar todos os campos. Felizmente, o DataSource tem a propriedade OnlyFetchActive, o qual controla o comportamento da query selecionando apenas os campos atualmente exibidos no formulário. Nota, você deve evitar usar isto com datasources editáveis, veja nos comentários deste post para maiores detalhes.
Quanto aos “?” no trace SQL – acontece devido ao uso dos placeholders. Isto geralmente melhora a performance das queries, criando um plano de execução e quardando para uso futuro. Mas é possível, e é necessário em alguns casos específicos, forçar o uso das literais (mostrar os valores reais na query). Isso pode ser feito usando o método literals na query.
[]s
Pichler
Olá,
outro dia eu estava navegando por ai e vi um artigo sobre mudar o estilo do table browser, o que é bastante útil, ainda mais quando se quer navegar entre os registros, apagá-los e etc…
O table browser nada mais é do que um formulário, com um DS que recebe como tabela a tabela common, ou seja, todas as outras são compatíveis, porque herdam common.
Bom, para fazer a simples alteração, basta:
AOT -> Forms -> SysTableBrowser -> Design -> Design e editar a propriedade “Window Type” alterando para “Standard”, pronto.
[]s
Pichler
Caros,
Li agora pouco no http://www.doens.be um artigo sobre como listar os campos obrigatórios de uma determinada tabela e resolvi compartilhar com vocês, eu já havia feito algo semelhante para um cliente que me pediu os campos obrigatórios para me gerar os dados para uma importação.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | static void CheckMandatoryFieldsOnTable(Args _args) { DictTable dictTable; DictField dictField; int i; TableId tableId = tablenum(custtable); ; dictTable = new DictTable(tableId); for (i=1 ; i<=dictTable.fieldCnt() ; i++) { dictField = new DictField(tableId, dictTable.fieldCnt2Id(i)); if (dictField.mandatory()) { info(dictField.name()); } } } |
[]s
Pichler
11 Feb
Posted by: Ricardo Pichler in: X++
Detalhes:
Versão: 2009
Data da publicação: 2/4/2010
Idioma: English
Tamanho: 298 KB
[]s
Pichler
Visão geral o artigo “Expressions in query ranges”, Axaptapedia.
Construção de uma query simples:
1 2 3 | query = new Query(); dsInventTable = query.addDataSource(tableNum(InventTable)); queryBuildRange = dsInventTable.addRange(fieldNum(InventTable, DataAreaId)); |
Critério simples:
Pesquisar o registro onde o itemID é B-R14.
queryBuildRange.value(strFmt('(ItemId == "%1")', queryValue("B-R14")));
Pesquisando registros onde o tipo é um serviço:
queryBuildRange.value(strFmt('(ItemType == %1)', any2int(ItemType::Service)));
Pesquisando registros onde o tipo é um serviço ou o itemID é B-R14.
queryBuildRange.value(strFmt('((ItemType == %1) || (ItemId == "%2"))', any2int(ItemType::Service), queryValue("B-R14")));
Pesquisando registros onde a data da modificação é depois de 01/01/200.
queryBuildRange.value(strFmt('(ModifiedDate > %1)', Date2StrXpp(01012000)));
Critérios complexos combinando condição OU e E
Pesquisando todos os registros aonde o tipo é um serviço ou item e que o ProjCategoryId for igual a Spares.
queryBuildRange.value(strFmt('((%1 == %2) || ((%1 == %3) && (%4 == "%5")))', fieldStr(InventTable, ItemType), any2int(ItemType::Service), any2int(ItemType::Item), fieldStr(InventTable, ProjCategoryId), queryValue("Spares")));
Condições WHERE referenciando a campos de multiplas tabelas
Para o exemplo abaixo, nós construimos uma query que consiste em um JOIN the dois datasources usando um EXIST JOIN.
query = new Query(); dsInventTable = query.addDataSource(tableNum(InventTable), tableStr(InventTable)); dsInventItemBarCode = dsInventTable.addDataSource(tableNum(InventItemBarCode), tableStr(InventItemBarCode)); dsInventItemBarCode.relations(true); dsInventItemBarCode.joinMode(JoinMode::ExistsJoin); // Add our two ranges queryBuildRange1 = dsInventTable.addRange(fieldNum(InventTable, DataAreaId)); queryBuildRange2 = dsInventItemBarCode.addRange(fieldNum(InventItemBarCode, DataAreaId));
Procurar todos os registros aonde o código de barras existir para um item e foi modificado depois que o item foi modificado.
queryBuildRange2.value(strFmt('(ModifiedDate > InventTable.ModifiedDate)'));
Perceba que SE nós tivéssemos adicionado nosso dataSource InventTable usando o seguinte código:
dsInventTable = query.addDataSource(tableNum(InventTable), "InventTableCustomName"); // Perceba que nós estamos modificando um nome diferente para o DataSource
Então a query deve aparecer como:
queryBuildRange2.value(strFmt('(ModifiedDate > InventTableCustomName.ModifiedDate)'));
Conditional joins
Nós iremos modificar levemente o exemplo anterior, para remover a adição automatica do relacionamento para o Join.
query = new Query(); dsInventTable = query.addDataSource(tableNum(InventTable), "InventTable"); dsInventItemBarCode = dsInventTable.addDataSource(tableNum(InventItemBarCode), "InventItemBarCode"); dsInventItemBarCode.joinMode(JoinMode::ExistsJoin); // Add our two ranges queryBuildRange1 = dsInventTable.addRange(fieldNum(InventTable, DataAreaId)); queryBuildRange2 = dsInventItemBarCode.addRange(fieldNum(InventItemBarCode, DataAreaId));
Usando as tecnicas acima, é possível criar queries com quase o mesmo tanto de flexibilidade como usando comandos SQL diretamente.
[]s
Pichler
Caros,
A um tempo atrás eu precisei debugar processos dos livros fiscais e por rodar em threds, eu não conseguia debugar.
A solução que adotei, foi essa abaixo:
1 2 3 4 5 6 7 8 | static void Job1(Args _args) { FBIExport_BR export; int jobCode = 5; ; export = new FBIExport_BR(FBIJOb_BR::construct(jobCode), new FBISqlExecutor_BR(FBIDatabaseConnectionFactory_BR::returnFBIDatabaseConnection())); export.run(); } |
A única mudança necessária é o código do job, que você deve mudar conforme o job que você quer executar.
[]s
Pichler
Para tal, nós precisamos setar certos valores nos parâmetros de impressão antes de rodar o relatório.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Variables PrintJobSettings printJobSettings; ReportRun myReportRun; ... // Recuperando os parâmetros do relatório printJobSettings = myReportRun.printJobSettings(); // Configurando nossos parâmetros printJobSettings.setTarget(PrintMedium::File); printJobSettings.preferredTarget(PrintMedium::File); printJobSettings.format(PrintFormat::PDF); printJobSettings.preferredFileFormat(PrintFormat::PDF); printJobSettings.fileName("c:\\attachment.pdf"); // Salvando os valores myReportRun.unpackPrintJobSettings(printJobSettings.packPrintJobSettings()); // Rodando o relatório myReportRun.run(); |
Antes de rodar o relatório, podemos configurar os valores da query:
1 2 3 4 5 6 7 8 | query = myReportRun.query(); qbds = query.dataSourceNo(1); qbds.range(1).value(_custTable.CustAccount); qbds.range(2).value(""); qbds.range(3).value(queryvalue(NoYes::Yes)); myReportRun.run(); |
Nota: Para usar uma impressora PDF como o “PDFCreator”, simplesmente configure o nome do dispositivo como:
1 | myReportRun.deviceName("PDFCreator"); |
Fonte: http://olondono.blogspot.com.
[]s
Pichler
2009 alertas aot args ax ax 4 ax 2009 ax report cache cep ceps certificação código datasource debug demo data DictTable download ep excel fieldID Funcional how do I instalação inventOnHand kernel functions label like localização odbc performance query random recid relatórios runtime sharepoint sql stored procedures system tables tabax Tips & Tricks vista word X++
WP Cumulus Flash tag cloud by Roy Tanck and Luke Morton requires Flash Player 9 or better.
| Bauru, Brazil | 1 |
| Saint Petersburg, Russian Federation | 1 |