Blog Listem

15 Kasım 2017 Çarşamba

AX 2012 - Multiselect Lookup

Bunun için AOT altında örnek bir form (tutorial_LookupMultiSelectGrid) ve hazır bir class var:

public class FormRun extends ObjectRun
{
    SysLookupMultiSelectCtrl msCtrl;
}


public void init()
{
    
    ...  
    super();
    ...
    
    msCtrl = SysLookupMultiSelectCtrl::construct(element, InventLocationIdExc, queryStr(InventLocationSRS));
    msCtrl.set(this.InventLocationList());
    ...
}

Listeyi aşağıdaki gibi alıp yukarıdaki init metod örneğindeki gibi okuyabiliriz.

container InventLocationList()
{
    Container           Ids,Names;
    InventLocation      location;
    int i;
    RecId               recId;

    for (i=1;i<=conLen(vInventLocationIdExc);i++)
    {
        recId = conPeek(vInventLocationIdExc,i);
        select firstOnly location
            where location.RecId == recId;
        Ids += location.RecId;
        Names += location.InventLocationId;
    }

    return [Ids,Names];
}

Pack metodda aşağıdaki gibi saklayabiliriz:

container pack()
{
    ...
    vInventLocationIdExc    = msCtrl.get();
    ...
}

Yukarıdaki MsCtrl.Get() metodu  RecId değerlerini verirken aşağıdaki de Field değerlerini verir:

container               c = msCtrl.getSelectedFieldValues();

14 Kasım 2017 Salı

AX 2012 - Form Grid kontrolüne InventDim ekleme

InventDim tablosunu form data source kısmına ekleyip inventDimId alanının bulunduğu tabloyla (bu örnekte adı SNBProductDemonte) InnerJoin yapın.

Form gride aşağıdaki gibi bir Group kontrol ekleyin:




Forma aşağıdaki kodları ekleyin:

public class FormRun extends ObjectRun
{
    InventDimCtrl_Frm_EditDimensions        inventDimFormSetup;
}

public void init()
{
    super();
    ...
    element.updateDesign(InventDimFormDesignUpdate::Init);
...

}


Object inventDimSetupObject()
{
    return inventDimFormSetup;
}

void updateDesign(InventDimFormDesignUpdate mode)
{
   InventDimParm inventDimParmVisible;

    switch (mode)
    {
        // Form Init
        case InventDimFormDesignUpdate::Init    :
            if (!inventDimFormSetup)
                inventDimFormSetup  = InventDimCtrl_Frm_EditDimensions::newFromForm(element);
                inventDimFormSetup.parmSkipOnHandLookUp( true);

                // Use the methods on InventDimParm
                // to set which dimensions to show when form is initialized
         //       inventdimparmvisible.inventsiteidflag       = true;
           //     inventdimparmvisible.InventLocationIdFlag   = true;
                inventDimFormSetup.parmDimParmVisibleGrid(inventDimParmVisible);

        // Datasource Active
        case InventDimFormDesignUpdate::Active  :
            inventDimFormSetup.formActiveSetup(InventDimGroupSetup::newItemId(SNBProductDemonte.ItemId)); 
            inventDimFormSetup.formSetControls( true);
            break;

        // Datasource Field change
        case InventDimFormDesignUpdate::FieldChange :
            inventDimFormSetup.formActiveSetup(InventDimGroupSetup::newItemId(SNBProductDemonte.ItemId)); 
            InventDim.clearNotSelectedDim(inventDimFormSetup.parmDimParmEnabled()); // InventDim is referring to datasource name
            inventDimFormSetup.formSetControls( true);
            break;

        default :
            throw error(strFmt ("@SYS54195", funcName()));
    }
}

InventDimId alanının olduğu tabloya aşağıdaki kodları ekleyin:

public boolean validateWrite()
{
    boolean ret;

    SNBProductDemonte.InventDimId = InventDim::findOrCreate(InventDim).InventDimId;
    ret = super();
  
    return ret;
}

public int active()
{
    int ret;
    ret = super();

    element.updateDesign(InventDimFormDesignUpdate::Active);
    return ret;
}

ItemId alanı modified metoduna aşağıdaki kodu ekleyin:

public void modified()
{
    super();

    element.updateDesign(InventDimFormDesignUpdate::FieldChange);
    InventDim.clearNotSelectedDim(element.inventDimSetupObject().parmDimParmEnabled());
}


Sistemde hazır bulunan InventDimParmFixed isimli Display menu item'i forma ekleyin.

Kaynak:
https://daxbeginners.wordpress.com/2014/08/05/how-to-dynamically-display-inventory-dimension/

Axapta - DateTime Alanlarda İki Gün Arasıda Saniye Kaçırmamak

DateTime alanlarda iki tarih arası rapor alırken ikinci tarihi bir sonraki günün ilk saniyesi olarak alıp <= yerine < kullanmak bir saniye dahi kaçırmamamızı sağlar:

fromDate = DateTimeUtil::newDateTime(FromDateEdit.dateValue(),0,DateTimeUtil::getCompanyTimeZone());
    toDate   = DateTimeUtil::newDateTime(ToDateEdit.dateValue()+1,0,DateTimeUtil::getCompanyTimeZone());

    while select count(RecId) from serviceOrderTable
                where serviceOrderTable.createdDateTime >= fromDate
                    && serviceOrderTable.createdDateTime < toDate



10 Kasım 2017 Cuma

AX 2012 - SSRS Raporda Nakli/Devreden Yekün ve Sayfa Toplamı

Maalesef SSRS'te nakli yekün ve sayfa toplamı olması gerekenden çetrefilli. Nakli yekün için bir blogdan (Peter ?), sayfa toplamı için de başka bir blogdan (Annette Theißen) faydalandım.

Nakli yekün ve sayfa toplamı alacağımız alan AccountingCurrencyAmountDebit olsun.

Devreden yekün için tablix kontrolümüze adı dCarry, valuesi aşağıdaki gibi olan bir alan ekliyoruz:

=RunningValue(Fields!AccountingCurrencyAmountDebit.Value,SUM,"LedgerTransListAccountDS")

veya koda göre gruplayacaksak:

=RunningValue(Fields!AccountingCurrencyAmountDebit.Value,SUM,"AccountNum_0")


Nakli yekün için de adı dCarryH olan aşağıdaki gibi bir alan ekliyoruz:

=RunningValue(Fields!AccountingCurrencyAmountDebit.Value,SUM,"AccountNum_0") - Fields!AccountingCurrencyAmountDebit.Value

Her iki alanın da visibility değerini no yapıyoruz. Alanlar gizli de olsa hesaplama yapacak.

Nakli yekün için Page Header kısmına valuesi aşağıdaki gibi olan bir alan ekliyoruz:

=First(ReportItems!dCarryH.Value)

Visibility değerini şarta bağlıyoruz (Böylece ilk sayfada nakli yekün olmayacak):

=Globals!PageNumber=1

Devreden yekün için de Page Footer kısmına da valuesi aşağıdaki gibi olan bir alan ekliyoruz:

=last(ReportItems!dCarry.Value)

Visibility değerini şarta bağlıyoruz (Böylece son sayfada devreden yekün olmayacak):

=Globals!PageNumber=Globals!TotalPages

Sayfa toplamı için iki data method ve variable eklememiz gerekiyor. Data method eklemek için treeview'de Designs altındaki Data Methods nodunda sağ klik - Add Data Method yapıyoruz. Ardından üzerine çift klik yaparak kod ekranını açıyoruz. Eklediğimiz kod aşağıda kırmızı çizili olan parça:

using System;
using System.Collections.Generic;
using System.Security.Permissions;
using System.Data;
using Microsoft.Dynamics.Framework.Reports;
using Microsoft.Dynamics.AX.Application.Reports;
public partial class LedgerTransListAccount
{
    static double previousTotal;
    static double pageTotal;
    static bool NewAccount;
    static string lastAccount;

     ...
   
 [DataMethod(), PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
    public static double PageTotal(double total)
    {
         if (NewAccount)
            return total;
         else
            return total - previousTotal;
    }

    [DataMethod(), PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
    public static double PreviousTotal(double total)
    {
        previousTotal = total;

        return 0;
    }
[DataMethod(), PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
    public static string Reset()
    {
        NewAccount = false;
        lastAccount = "";

        return "";
    }

    [DataMethod(), PermissionSet(SecurityAction.Assert, Name = "FullTrust")]
    public static string FollowAccount(string account)
    {
        if (lastAccount != "" && lastAccount != account)
            NewAccount = true;
        lastAccount = account;

        return account;

    }
      
}

Page Footera Bir textbox ekliyoruz:

=PreviousTotal(First(ReportItems!dCarryH.Value))

Bu textbox'un visible değerini false yaparsak maalesef hesaplama yapmaz. Display formatı number seçip Show zero as combobox değerini boşluk yapın (None değil!!).

Sayfa toplamını göstermek için bir alan daha ekliyoruz:

=PageTotal(last(ReportItems!dCarry.Value))

Neden yukarıdaki gibi fazladan bir textbox kullandık diyenler için; SSRS malesef expression parametre olarak iki farklı alanı kabul etmiyor.

Sayfa başına bir Textbox ekliyoruz:

=Reset()




8 Kasım 2017 Çarşamba

AX 2012 - Ürün reçetesi açılımı

Bunun için Christian Silva'nın yazdığı kodları kullandım. Yazar birim çevrimlerini ve renk /bedeni dikkate almamış. Reçetede gram olarak kullanılan bir yarı-mamulün alt reçetede kg'ya çevrilmesi gerekebiliyor. Ben bunları da ekledim:

class SNBBOMExplode
{
    SNBBOMExplodeTmp    tmpBOM;
    SNBBOMExplodeData   bomdata;
    ItemId              itemId;
    EcoResItemSizeName  inventSizeId;
    EcoResItemColorName inventColorId;
    InventSiteId        inventSiteId;
}

boolean hasChild(ItemId _itemId)
{
    BOMVersion  bomVersion;
    ;

    //Check if the item is also a BOM item.
    select firstonly bomVersion
            where bomVersion.ItemId == _itemid
            && bomVersion.Active
            && bomVersion.FromDate <= systemdateget ()
            && (!bomVersion.ToDate || bomVersion.ToDate >= systemdateget ());

    if (bomVersion.RecId)
        return true ;

    return false ;
}

private int InsertParentItem(ItemId _itemId, int _level)
{
    InventTable inventTable;
    ;

    //Gets the parent information and then insert on TmpBOMExplode Table with level 0.
    select firstOnly inventTable where inventTable.ItemId == _itemId;

    tmpBOM.ItemId = _itemId;
    tmpBOM.Level = _level;
    tmpBOM.BOMQty = 1 ;
    tmpBOM.HasChild = this.hasChild(_ItemId);
    tmpBOM.insert();

    return _level+ 1 ;
}

void itemExplode(ItemId _ItemId, int _level = 0, BOMQty _bomQty = 1)
{
    BOM         bomTable;
    InventTable inventTable;
    BOMVersion  bomVersion;
    InventDim   inventDim;
    BOMQty      qtyS;

    ;

    //Insert parent Item
    if (_level == 0)
        _level = this.InsertParentItem(_ItemId, _level);

    //Verifies if the Item exists in BOMVersion Table.
    //The item must be active and not expired.
    select firstonly bomVersion
            where bomVersion.ItemId == _itemid
            && bomVersion.Active
        exists join inventDim
            where inventDim.inventDimId == bomVersion.InventDimId &&
                  (inventDim.InventColorId == inventColorId || inventColorId == "") &&
                  (inventDim.InventSizeId == inventSizeId || inventSizeId == "");
        //    && bomVersion.FromDate <= systemdateget()
        //    && (!bomVersion.ToDate || bomVersion.ToDate >= systemdateget());

    if (bomVersion.RecId)
    {
        //Every item on BOMVersion has a BOMId which is used to show
        //which products belong to a BOM Item.
        While select bomTable
            where bomTable.BOMId == bomVersion.BOMId
            join inventTable
            where bomTable.ItemId == inventTable.ItemId
        {
            //Insert the items that compose the BOM Item with level 1.
            tmpBOM.ItemId    = bomTable.ItemId;
            tmpBOM.RefItemId = bomVersion.ItemId;
            tmpBOM.BOMQty    = bomTable.BOMQty / bomTable.BOMQtySerie * _bomQty;
            tmpBOM.Level     = _level;
            tmpBOM.UnitId    = bomTable.UnitId;
            tmpBOM.HasChild  = this.hasChild(bomTable.ItemId);
            tmpBOM.MainItemId = this.parmItemId();
            tmpBOM.insert();

            //This method is used to check if the BOM Item is composed by
            //another BOM Item, case true it will call the method recursively
            // with level 2.
            if (tmpbom.HasChild == NoYes::Yes)//--- unit conversion ---
            {

                qtyS =  UnitOfMeasureConverter::convert(
                            tmpBOM.BOMQty,
                            UnitOfMeasure::unitOfMeasureIdBySymbol(tmpBOM.UnitId),
                            UnitOfMeasure::unitOfMeasureIdBySymbol(bomTable.inventTable().inventUnitId()),
                            NoYes::Yes,
                            InventTable::itemProduct(tmpBOM.ItemId));

                this.itemExplode(bomTable.ItemId, _level+ 1, qtyS);
            }
        }
    }
}

void linkTables(SNBBOMExplodeTmp _tmp)
{
   tmpBOM.linkPhysicalTableInstance(_tmp);
}

EcoResItemColorName parmInventColorId(EcoResItemColorName _inventColorId = inventColorId)
{
    inventColorId = _inventColorId;

    return inventColorId;
}

EcoResItemSizeName parmInventSizeId(EcoResItemSizeName  _inventSizeId = inventSizeId)
{
    inventSizeId = _inventSizeId;

    return inventSizeId;
}

ItemId parmItemId(ItemId _itemId = ItemId)
{
    ItemId = _itemId;

    return ItemId;
}

SNBBOMExplodeTmp  parmSNBBOMExplodeTmp()
{
    select * from tmpBOM;
    return TmpBOM;
}

void run()
{
    delete_from tmpBOM;
    this.itemExplode(ItemId,0);
}


Class'da kullanılan SNBBOMExplodeTmp isimli tempDB tipli tablonun yapısı:

BOMQty     BOMQty
HasChild   NoYesId
ItemId     ItemId
Level      BOMLevel
MainItemId ItemId
RefItemId  ItemId
UnitId     UnitOfMeasureSymbol

Örnek kullanımı:

         SNBBOMExplodeTmp    tmpBOM;
    SNBBOMExplode       bomExp = new SNBBOMExplode();
    

    bomExp.parmItemId(list.ItemId);
    bomExp.linkTables(tmpBOM);
    bomExp.parmInventColorId(list.InventColorId);
    bomExp.parmInventSizeId(list.InventSizeId);
    bomExp.run();