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!

segunda-feira, 28 de agosto de 2017

Alterar Servidor de SSRS - Dynamics AX 365 For Finance and Operations

Antes, no AX2012, para que pudêssemos alterar o Servidor de Report, tinhamos que faze-lo direto em um formulário que continha os endereços das URLs pertinentes ao SSRS. No DAX365FFO isso mudou, a alteração é direto no WebConfig e existe um pacote pronto para isso!

Os procedimentos abaixo, foram executados no servidor que hospeda o IIS.

Para alterar o nome do Servidor de Reports do DAX365FFO, execute os seguintes passos:

1 - Abra como administrador o PowerShell. Geralmente fica localizado em: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe

2 - Execute o seguinte pacote, seguido do nome do server:
           Ambiente On-Premises:
                  C:\Packages\Plugins\AxReportVmRoleStartupTask\UpdateSsrsMachineNameInAosWebConfig.ps1 ServerName

           Ambiente Azure (em VMs contoso, a partição é a C:  e deve-se utilzar este comando)
          J:\AOSService\PackagesLocalDirectory\Plugins\AxReportVmRoleStartupTask\UpdateSsrsMachineNameInAosWebConfig.ps1 ServerName

em um ambiente Azure, o comando deve ficar parecido com:
         
         

3 - Executado o comando, vá no WebConfig e verifique se as seguintes tags estão como abaixo, com o novo Nome:

                      <add key="BiReporting.PersistentVirtualMachineIPAddressSSRS" value="ServerName" />

     <add key="PersistentVirtualMachineIPAddressSSRS" value="ServerName" />

Quaisquer dúvidas, postem nos comentários que tentarei responder!