quinta-feira, 18 de outubro de 2018

Como reproduzir a criação do XML da NFe, de uma nota já enviada para a SEFAZ

Para isso basta colocar o seguinte código, no método main de uma classe com a propriedade RunOn como Server, colocar o RecId da FiscalDocument_BR correspondente no parâmetro do método find em seguida pressionar F5:

public server static void Main(Args _args)
{
    EFDocMsgStringStream_BR EFDocMsgStringStream_BR = new EFDocMsgStringStream_BR();
    EFiscalDocumentList_BR EFiscalDocumentList_BR = EFiscalDocumentList_BR::construct();
    EFDocMsgFormat_XmlSubmitV4_BR EFDocMsgFormat_XmlSubmitV4_BR = new EFDocMsgFormat_XmlSubmitV4_BR();
    EFiscalDocument_BR EFiscalDocument_BR;
    ;

    EFiscalDocument_BR = EFiscalDocument_BR::construct(FiscalDocument_BR::find(5640230734,false));
    EFiscalDocumentList_BR.add(EFiscalDocument_BR);
    EFDocMsgFormat_XmlSubmitV4_BR.write(EFDocMsgStringStream_BR, EFiscalDocumentList_BR);
   
    info(EFDocMsgStringStream_BR.toString());
}


quinta-feira, 12 de julho de 2018

Como desabilitar a exclusão de índices SQL, criados fora da AOT - Microsoft Dynamics AX 2012 R3

É sabido que a sincronização do Banco de Dados do AX, exclui todos os índices que por ventura tenham sido criados fora da AOT, ou interface de desenvolvimento do AX.

Navegando pelo LCS encontrei este KB, que torna possível manter estes índices na base:




Ao meu ver, esta é uma forma da Microsoft viabilizar uma maior flexibilidade na criação de índices, já que o Morphex tem algumas limitações.

Como observação, cuidados inerentes a estes índices criados por fora da AOT, devem ser tomados através do SGBD do Sql Server, pois o AX não os enxergará em suas rotinas de manutenção de Banco de Dados!

sábado, 16 de dezembro de 2017

Botão "Editar" da janela de Log de Informações não existe mais. O que fazer? - Microsoft Dynamics 365 FFOEE

Uma das coisas as quais senti falta nas primeiras horas de desenvolvimento na nova versão do ERP Microsoft Dynamics, foi do botão Editar da janela de log de informações do sistema. No Dynamics AX 2012 este botão é uma mão na roda para que precisa saber que evento gerou determinada mensagem. Abaixo uma imagem deste botão:


Era só clicar nele, que o código que originou esta mensagem seria exibido no Morphex.


A maneira que encontrei de contornar tal problema, foi utilizar o método add da classe Info. É por lá que cada mensagem a ser exibida para o usuário, é passada. Basta adicionar um breakpoint  no método e navegar pelo callstack para descobrir a origem da mensagem.



Agora será fácil saber de onde cada mensagem está sendo chamada, no Microsoft Dynamics 365 For Finance and Operation, Enterprise edition!! (belo nome)

terça-feira, 28 de novembro de 2017

Bug na execução em CIL do método MapIterator.find() - Microsoft Dynamics AX 2012

Hoje analisando um problema na execução da Absorção de Custos foi constatado um problema na atribuição dos vouchers da tabela de Custos Absorvidos (ACOProdOverHeadCostTrans_BR). Fazendo uma análise mais aprofundada verificou-se que o problema só ocorria quando o processo era executado em lote.

Com isso busquei no LCS e encontrei um KB que corrige um cenário parecido, onde o mesmo atuava na mesma classe em que estava fazendo a análise. O KB é o de número e descrição 3218475, Bug Id 3806370: Brazil/BRA: The "Cost absorption journal" generates transactions with blank voucher when it is posted via a batch job. 

Percebendo que em meu ambiente o citado KB já consta, verifiquei onde mais o método substituído (AcoJournalCheckPost_BR.getvoucher()) ainda estava sendo usado e o retirei utilizando a solução proposta pela MS.

Com o problema corrigido, fui tentar entender o que ocorreu, e verifiquei que o método MapIterator.find() não funciona adequadamente quando executado em CIL. Por isso a Microsoft optou por usar o Map.lookup()  na resolução do problema citado anteriormente.

Fiz uma classe que exemplifica o que ocorreu:

              Passo 1 -  Copie o código abaixo em seu ambiente, e atualize a CIL

class Xppil_Test
{
}

public server static void Main(Args _args)
{
    XppILExecutePermission permission = new XppILExecutePermission();
    permission.assert();

    runClassMethodIL(classStr(Xppil_Test),staticMethodStr(Xppil_Test,RunCode),conNull());

    Xppil_Test::RunCode(conNull());
}

public static container RunCode(container _con)
{
    date dateLocal;
    Xppil_Test xppil_Test = new Xppil_Test();

    if(xSession::isCLRSession())
    {
        info(strFmt("Versão executando em CIL:"));
        xppil_Version.findTest();
    }
    else
    {
        info(strFmt("Versão executando em X++:"));
        xppil_Version.findTest();        
    }

    return conNull();
}

private void findTest()
{
    Map                         voucherUsed;
    MapIterator it;     
        
    voucherUsed = new Map(Types::String,Types::String);
    voucherUsed.insert("PO0001", "VO0001");
    voucherUsed.insert("PO0002", "VO0002");
    voucherUsed.insert("PO0003", "VO0003");
    voucherUsed.insert("PO0004", "VO0004");
        
    it = new MapIterator(voucherUsed);
        
    if (it.find("PO0001"))
    {
        info(it.value());
    }
        
    if (it.find("PO0002"))
    {
        info(it.value());
    }
      
    if (it.find("PO0003"))
    {
        info(it.value());
    }
      
    if (it.find("PO0004"))
    {
        info(it.value());
    }   
}

              Passo 2 -  Execute o método Main da classe e verifique os resultados


A classe executa o mesmo método duas vezes, uma em CIL e a outra em X++. Perceba que o MapIterator.find() sempre retorna o VO0001 quando executado em CIL, diferentemente de quando executado em X++.  

Portanto, é indicado usar sempre o Map.lookup(), ao invés do MapIterator.find(). Use o seguinte link para aprender a como usar o Map.lookup():

quarta-feira, 27 de setembro de 2017

Agendamento Automático da Execução em Lotes - Microsoft Dynamics AX

Abaixo segue o exemplo de um código, ao qual cria um agendamento de execução em lotes de maneira automática, ou seja, sem a ação direta do usuário. A classe a ser utilizada deve estender RunbaseBatch e estar funcionando da maneira convencional! (chamando o agendamento via .prompt())

No exemplo também implementei a alteração da hora de inicio, sendo que o mesmo será executado somente uma vez!
Caso o seu cenário mude, deve-se estudar os demais métodos da classe SysRecurrence, com a finalidade de alterar os outros parâmetros de recorrência!

Segue código de exemplo:

YourRunBaseBatchClass yourRunBaseBatchObj = new YourRunBaseBatchClass();

yourRunBaseBatchObj.batchInfo().parmBatchExecute(NoYes::Yes);
yourRunBaseBatchObj.parmValue(args.parm());
// Set the recurrence data
sysRecurrenceData = SysRecurrence::defaultRecurrence();
sysRecurrenceData = SysRecurrence::setRecurrenceEndAfter(sysRecurrenceData,0);
yourTable = YourTable::find();
switch (yourTable.SysRecurrenceUnit)
{
case SysRecurrenceUnit::Day:
sysRecurrenceData = SysRecurrence::setRecurrenceStartDateTime(sysRecurrenceData, DateTimeUtil::addDays(DateTimeUtil::utcNow(), yourTable.Counting)); // Set range of recurrence
break;
case SysRecurrenceUnit::Hour:
sysRecurrenceData = SysRecurrence::setRecurrenceStartDateTime(sysRecurrenceData, DateTimeUtil::addHours(DateTimeUtil::utcNow(), yourTable.Counting)); // Set range of recurrence
break;
case SysRecurrenceUnit::Minute:
sysRecurrenceData = SysRecurrence::setRecurrenceStartDateTime(sysRecurrenceData, DateTimeUtil::addMinutes(DateTimeUtil::utcNow(), yourTable.Counting)); // Set range of recurrence
break;
}
yourRunBaseBatchObj.batchInfo().parmBatchHeader().parmRecurrenceData(sysRecurrenceData);
yourRunBaseBatchObj.batchInfo().parmCaption("Batch Job Description");
yourRunBaseBatchObj.doBatch();


Qualquer dúvida, por favor poste na área de comentários!

terça-feira, 26 de setembro de 2017

KB NFE 4.0 - Dynamics AX 2012 R3

Já foi liberado o KB referente à NFE 4.0. Ele pode ser baixado através do link:

https://fix.lcs.dynamics.com/Issue/ReleasedFeature?bugId=3801209&qc=67e6a13267fc0900ff4eb7f5e85929b74b795d5d667871bd853ee7b43a1acf84


Não é necessária a instalação do Cumulative Update 13. O mesmo pode ser instalado separadamente, em qualquer AX 2012 R3.