quinta-feira, 27 de dezembro de 2007

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));
}


Nenhum comentário: