quinta-feira, 27 de dezembro de 2007

Blog sobre AX

Alguns blog que frequento, são atualizados com alguma frequência:

http://axaptafreak.blogspot.com/ blog mais antigo que eu frequento
http://axaptabuilder.blogspot.com/ esse blog não é atualizado a 1 ano, mas tem ótimas informações sobre AX + VSS
http://blogs.msdn.com/dpokluda/ ótimos posts sobre Test Units ultimamente
http://blogs.msdn.com/palle_agermark/ também frquento a tempos.

Um recado para quem frequenta o blog: deixem coments nos posts para sabermos quem são vocês!!! - ja que no Brasil não somos muitos.

Abs,
Matiazo

Job para migração de produtos utilizando ADO

Feliz natal a todos (e talvez poucos!) que frequentam o blog. Esse ano completou 4 anos que eu trabalho com Ax (antigo Axapta) e é claro que nesse tempo todo trabalhando com o sistema, a cabeça ferve de ideias e soluções para todos os problemas encontrados no dia dia.

Um dos que mais me incomodavam, era a falta de uma maneira simples de carregar uma tabela de produtos, seja no começo da implantação, ou para uma demo mais aprofundada. A algum tempo escrevi um job que se utiliza das classes .Net para fazer um select num excel e importar os produtos de forma infinitamente mais rápida que a ferramenta de importação de tabelas do Ax.
Essa importação tem a vantagem de poermos trabalhar com tabela simples com todos os campos em colunas, não do conjuntos de tabelas: inventtable + InventItemLocaltion + inventTableModule para Estoque, Compras e Vendas, que são necessárias serem criadas/importadas para que o produto apareça no form de produto, uma conta simples, par aimportar um produto voce precisaria criar um excel contendo essas 3 tabelas e criar:
1. Um linha de produto na pasta InventTable
2. 3 Linhas para o mesmo produto criado na pasta 1 para preços (e todos campos que estão na aba Preço e Quantidade) de compra, venda e estoque na pasta InventTableModule
3. Uma linha ligada ao produto 1 na pasta InventItemLocation.

Para construir o job eu utilizei a classe AxInventTable, ela encapsula toda a logica para criação de produtos, as classes Ax são as classes que devem ser utilizadas quando se deseja criar alguma integração com o Ax ja que esse encapsulamento garante a criação correta das entidades. No caso dos produtos, para cada produto que é gravado, através do .save() ela ja cria os registros respectivos nas tabelas mostradas acima.

Para manter o job simples de ler, acabei trabalhando com comandos de macros definido constantes para cada indice de coluna que eu gostaria de trabalhar, assim o código fica mais legível e facil de manter.

No exemplo, o job cria o produto com as seguintes características:
1. Item id
2. Name
3. Item group
4. Item Type
5. Inventory Model group
6. Dimension group
7. Packing Quantity (quantidade de unidades por embalagem)
8. Net Weight (peso liquido)
9. Tara (o peso bruto é dado pral tara + peso liquido)
10. Classificação fiscal
11. Coluna com % de IPI

Para o IPI eu segui uma lógica simples, para cada porcentagem de IPI, foi criado um grupo correspondente dentro do Ax, no caso do exemplo somente 10%, mas isso poderia ser expandido para os IPI utilizados pelo cliente.

Utilizando deste tipo de importação (e das classes Ax), é possível configurar uma empresa com produtos, clientes e fornecedores para fazer workshops, demos, ou mesmo carga inicial de implantação de uma maneira simples e rápida com um pouco esforço de programação.

Ultimamente, todos os workshops (tanto em pre-venda ou início de implantação) que eu ja faço com meus clientes, ja trabalho com os dados reais, mesmo que básicos, falando a lingua do cliente fazendo com que a comunicação com os usuários e o entendimento do sistema seja feito de uma maneira simples para quem não conhece o sistema fazendo inclusive o usuário ir se acostumando com o sistema desde o início.


O job segue abaixo:

static void migrarProdutos(Args _args)
{
#define.ItemId (0) // A
#define.ItemName (1) // B
#define.ItemGroupId (2) // C
#define.ItemType (3) // D
#define.ModelGroupId (4) // E
#define.DimGroupId (5) // F
#define.TaxPackagingQty (6) // G
#define.NetWeight (7) // H
#define.TaraWeight (8) // I
#define.TaxFiscalClassificationId (9) // J
#define.PctIPI (10)// L


CCADOConnection adoexcel = new CCADOConnection();
CCAdoxCatalog adoCatalog = new CCAdoxCatalog();
COM adoxCatalog = new COM('ADOX.Catalog');
CCADORecordSet adoRecordSet = new CCADORecordSet();
CCADOFields adoFields;
int i;
int j;

// ------ Objetos usados importação
AxInventTable axInventTable;

InventItemGroup inventItemGroup;
TaxFiscalClassification_BR fiscalClassification;

ItemId itemId;
TaxItemGroup salesIaxItemGroup;
// ------ Objetos usados importação
;

adoexcel.connectionString("Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+
"D:\\Documentos\\rm\\Projetos\\\\MigraProdutos.xlsx ;Extended Properties='Excel 8.0;HDR=Yes;IMEX=1'");
adoexcel.open();
adoxCatalog.activeConnection(adoexcel.connection());
adoCatalog.adoxCatalog(adoxCatalog);
adoRecordSet.open(@"SELECT * FROM [Plan1$]", adoexcel);
adoFields = adoRecordSet.fields();

ttsbegin;

while (! adoRecordSet.EOF())
{
if(adoFields.itemIdx(#ItemId).value())
{
itemId = adoFields.itemIdx(#ItemId).value();
if(!InventTable::find(itemId))
{
axInventTable = new AxInventTable();

axInventTable.parmItemId (adoFields.itemIdx(#ItemId) .value());
axInventTable.parmItemName (adoFields.itemIdx(#ItemName) .value());
axInventTable.parmTaxPackagingQty (adoFields.itemIdx(#TaxPackagingQty) .value());
axInventTable.parmNetWeight (adoFields.itemIdx(#NetWeight) .value());
axInventTable.parmTaraWeight (adoFields.itemIdx(#TaraWeight) .value());
axInventTable.parmTaxFiscalClassificationId(adoFields.itemIdx(#TaxFiscalClassificationId).value());

axInventTable.axInventTableModule_Sales().parmPrice(100.00);

if(adoFields.itemIdx(#PctIPI).value() == 10)
{
if(adoFields.itemIdx(#ItemType).value() == 'BOM')
{
salesIaxItemGroup = 'V-PA10'; // Venda produto acabado IPI 10%
}
else if (adoFields.itemIdx(#ItemType).value() == 'Item')
{
salesIaxItemGroup = 'V-MP10'; // Venda materia prima IPI 10%
}
else// if (adoFields.itemIdx(#ItemType).value() == 'Service') ou em branco
{
salesIaxItemGroup = "";
}
}

axInventTable.axInventTableModule_Sales().parmTaxItemGroupId(salesIaxItemGroup);

if(adoFields.itemIdx(#ItemType).value() == 'BOM')
{
axInventTable.parmItemType(ItemType::BOM);
}
else if (adoFields.itemIdx(#ItemType).value() == 'Item')
{
axInventTable.parmItemType(ItemType::Item);
}
else if (adoFields.itemIdx(#ItemType).value() == 'Service')
{
axInventTable.parmItemType(ItemType::Service);
}
else // se nada é especificado, cria o produto como ITEM
{
axInventTable.parmItemType(ItemType::Item);
}

// Cria o grupo de produto caso não exista
inventItemGroup = inventItemGroup::find(adoFields.itemIdx(#ItemGroupId).value());
if(!inventItemGroup)
{
inventItemGroup.ItemGroupId = adoFields.itemIdx(#ItemGroupId).value();
inventItemGroup.insert();
}

// Cria a classificação fiscal caso não exista
select fiscalClassification
where fiscalClassification.FiscalClassificationId == adoFields.itemIdx(#TaxFiscalClassificationId).value();

if(!fiscalClassification)
{
fiscalClassification.FiscalClassificationId = adoFields.itemIdx(#TaxFiscalClassificationId).value();
fiscalClassification.insert();
}

axInventTable.parmItemGroupId(adoFields.itemIdx(#ItemGroupId).value());
axInventTable.parmModelGroupId("CUSMED"); // Grupo de modelo de estoque fixo
axInventTable.parmDimGroupId("Std-Dim"); // Grupo de dimensões de estoque fixo
axInventTable.save();
j++;
}
}
adoRecordSet.moveNext();
}
ttscommit;

info(strfmt('Items criados %1',j));
}


quinta-feira, 20 de dezembro de 2007

X++ - Excel via OleDB direto no AX

Saudações a todos!

O Microsoft Dynamics AX dispõe de várias formas de integração.

Entre elas, existe a opção de utilizar o . NET Framework diretamente no código X++, instanciando objetos dos namespaces desejados para ler os dados diretamente da base através do ADO.Net.

A discussão sobre integração surgiu originalmente no fórum MSDN, onde existe um tópico aberto sobre importação de dados para o DAX pelos variados meios, seja AIF, Excel table (que não é recomendável para Itens, vide tópico).
Vale lembrar que a participação de todos os profissionais do ramo nesse fórum é essencial para que possamos construir uma base de conhecimento, com uma "cara" mais prática, fortalecendo nossas referências no mercado.

Voltando ao assunto principal:

O método de acesso é realizado através do .Net framework.

As referências devem ser adicionadas no node
References do AOT.
Ex. System.Data / System.Data.resources / System.Data.SqlXml e assim por diante.

static
void MeuJob(Args _args)

{

System.Data.OleDb.OleDbConnection connection;
System.Data.OleDb.OleDbCommand command;
System.Data.OleDb.OleDbDataReader dr;
str id;
str nome;
str c;
str strSql;

c = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Dados.xls;Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\";";

// O parametro HDR determina se a primeira linha contem os nomes de colunas

// "IMEX=1;" lê os dados como texto.


connection = new System.Data.OleDb.OleDbConnection();
connection.set_ConnectionString(c);
connection.Open();

strSql = "SELECT * FROM [MinhaTabela$]";

//MinhaTabela corresponde ao nome da Planilha seguido por $ e entre []s.

command = new System.Data.OleDb.OleDbCommand(strSql, connection);
dr = command.ExecuteReader();


while (dr.Read())
{
id = dr.get_Item(0);
nome = dr.get_Item(1);
info(strfmt("%1 - %2",id,nome));
}
dr.Close();
}

Caso haja qualquer outra fonte de dados suportada pelos NameSpaces System.Data.* , seja Sql, OleDB ou ODBC, é só procurar o meio de conectar.

Uma fonte interessante é o site www.connectionstrings.com que comporta uma lista com as strings de conexão, bem como suas variações para quase todos os SGBDs disponíveis no mercado.

Aproveitando a época, eu gostaria de deixar um Feliz Natal e um Ótimo 2008 a todos que prestigiam nossa casa e compartilham as idéias.

Um abraço!

Nota Fiscal Eletrônica - função de quebra de nota fiscal por linhas do pedido de venda

A nota fiscal eletrônica traz uma funcionalidade interessante de que faz a quebra dos pedidos de venda por informações contidas nas linhas.

A princípio essa quebra esta apenas disponível quando o parametro de quebra por código de serviço esta ativo.





















Porém, com uma pequena alteração, é possível fazer com que o sistema quebre uma nota fiscal por qualquer campo disponível na linha do pedido de venda mesmo que a empresa não vena serviços.

Basta localizar o grupo chamado InvoiceSplit e adicionar o campo, por exemplo PackingUnit, que é a unidade da embalagem, fazendo isso, o sistema vai quebrar as notas fiscais quando houver diferentes tipos de embalagens para as linhas do pedido de venda.

Até a proxima,

Dynamics AX SP2 para o Brasil

Em novembro foi lançado o SP2 para a localização do AX, esse service pack tras novas funcionalidades localizadas para o AX que não estavam disponíveis anteriormente:

  • Diários de Notas Fiscais (Vendor invoice jourals) agora estão localizados, isto significa que é possivel entrar com notas fiscais e ter os impostos contabilizados e registrados corretamente dentro da lei brasileira.
  • Summary Update agora agrupa corretamente tanto pedidos de compra como pedidos de venda levando em considesções fiscais importantes como CFOP, Tipo de Documento Fiscal, etc..

Também contém 2 novas funcionalidades que cobrem mudanças recentes da lei ou mudanças que estão para entrar em vigor:

  • Nota Fiscal Eletrônica para cidade de São Paulo
  • Campos e formatação da imformatação requeria pelo Ato Cotepe/SPED Fiscal

Sobre a arquitetura de software e como tornar-se um arquiteto.

Recebi uma boa indicação sobre a profissão de arquiteto de software, para que esta nessa área ou gostaria de saber mais, segue o link.

http://www.microsoft.com/brasil/msdn/arquitetura/journal/Profile_Pat_Helland.mspx