12 Aralık 2018 Çarşamba

AX 2012 - Son maliyet fiyatı

Metodu InventTable veya ItemId alanı olan herhangi bir tabloya koyabilirsiniz:

public CostPrice SNBfindLastPrice(DatePhysical _date = systemDateGet(),InventDim _inventdim = null)
{

    InventTrans           inventTrans;

    InventTransOrigin     origin;
    InventDim             inventdim;
    LineAmount            purchprice;
    RecId                 OK = false;
    InventDimParm         dimParm;
    InventDim             dimJoin;


    dimparm.initFromInventDim(_inventdim);


    select firstOnly CostAmountAdjustment,CostAmountPosted,Qty from inventTrans

                order by inventTrans.DateClosed desc,inventTrans.DateFinancial desc
            where inventTrans.ItemId == this.ItemId &&
                  !inventTrans.ReturnInventTransOrigin &&
                 inventTrans.DateClosed != dateNull() &&
                 inventTrans.DateClosed <= _date
        exists join origin
            where origin.RecId == inventTrans.InventTransOrigin &&
                  origin.ReferenceCategory == InventTransType::SummedUp
        #InventDimExistsJoin(inventTrans.InventDimId,dimJoin,_inventdim,dimParm);
    OK = inventTrans.RecId;

    if (!OK)

    {
        select firstOnly CostAmountAdjustment,CostAmountPosted,Qty from inventTrans
                    order by inventTrans.DateFinancial desc
                where inventTrans.ItemId == this.ItemId &&
                      !inventTrans.ReturnInventTransOrigin &&
                      inventTrans.Qty > 0 &&
                      inventTrans.DateFinancial <= _date
            exists join origin
                where origin.RecId == inventTrans.InventTransOrigin &&
                      origin.ReferenceCategory == InventTransType::Purch
            #InventDimExistsJoin(inventTrans.InventDimId,dimJoin,_inventdim,dimParm);
        OK = inventTrans.RecId;
    }
    if (!OK)
    {
        select firstOnly CostAmountAdjustment,CostAmountPosted,Qty from inventTrans
                    order by inventTrans.DateFinancial desc
                where inventTrans.ItemId == this.ItemId &&
                      inventTrans.Qty > 0 &&
                      inventTrans.DateFinancial <= _date
            exists join origin
                where origin.RecId == inventTrans.InventTransOrigin &&
                      origin.ReferenceCategory == InventTransType::SummedUp
            #InventDimExistsJoin(inventTrans.InventDimId,dimJoin,_inventdim,dimParm);
        OK = inventTrans.RecId;
    }
    if (!OK)
    {
        select firstOnly CostAmountAdjustment,CostAmountPosted,Qty from inventTrans
                    order by inventTrans.DateFinancial desc
                where inventTrans.ItemId == this.ItemId &&
                      inventTrans.Qty > 0 &&
                      inventTrans.DateFinancial <= _date
            exists join origin
                where origin.RecId == inventTrans.InventTransOrigin &&
                      ( origin.ReferenceCategory == InventTransType::InventTransaction ||
                        origin.ReferenceCategory == InventTransType::BOMMain)
            #InventDimExistsJoin(inventTrans.InventDimId,dimJoin,_inventdim,dimParm);
    }
    if (inventTrans.Qty != 0)
        return  abs( (inventTrans.CostAmountAdjustment+inventTrans.CostAmountPosted ) / inventTrans.Qty );
    else
        return 0;
}

11 Ocak 2018 Perşembe

AX 2012 - Uyumsoft E-fatura servisini kullanma

Önce Uyumsoft'un WSDL adresine (https://efatura.uyumsoft.com.tr/Services/Integration?wsdl) daha önce bloğumda bahsettiğim şekilde bağlanan bir servis referansı oluşturun. Servis referansındaki App.Config dosyasına aşağıda kırmızı ile işaretlediğim parametreleri ekleyin. Bunları eklemediğiniz takdirde Uyumsoft varsayılan değer olan 65.536'dan büyük bloklar göndereceği için hata alacaksınız:

 <binding name="BasicHttpBinding_IIntegration"  maxBufferSize="2147483647" maxReceivedMessageSize="2147483647">

class SNBuyum
{
    uyumAX.uyumServis.IntegrationClient wsClient;
    uyumAX.uyumServis.PagedQueryContext pq;
    uyumAX.uyumServis.SystemUsersResponse res;
    uyumAX.uyumServis.PagedResponseOfSystemUser s;
    uyumAX.uyumServis.SystemUser[] u;
    uyumAX.uyumServis.SystemUser u2;

    System.ServiceModel.Description.ClientCredentials clientCredentials;
    System.ServiceModel.Security.UserNamePasswordClientCredential userPass;

    EInvoiceTRParameters                param;
}


void getEinvoiceUserList()
{
    CLRObject                             clientType;
    int i,j,k,l;
    System.Exception ex;


    new InteropPermission(InteropKind::ClrInterop).assert();

    param = EInvoiceTRParameters::find();

    clientType = CLRInterop::getType("uyumAX.uyumServis.IntegrationClient");
    wsClient = AifUtil::createServiceClient(clientType,"https://efatura.uyumsoft.com.tr/services/Integration");

    clientCredentials = wsClient.get_ClientCredentials();

    userPass = clientCredentials.get_UserName();
    userPass.set_UserName(param.UserID);
    userPass.set_Password(param.Password);

    pq = new uyumAX.uyumServis.PagedQueryContext();
    pq.set_PageIndex(0);


    try
    {
        res = wsClient.GetEInvoiceUsers(pq);

        s = Res.get_Value();

         i =   s.get_TotalPages();



        info(strfmt("%1",i));
        for (l=1;l<=i;l++)
        {
            pq.set_PageIndex(l);
            res = wsClient.GetEInvoiceUsers(pq);
            s = Res.get_Value();
            U = s.get_Items();
            k = u.get_Count();
            info(strFmt("%1",k));

            for (j=0;j<k;j++)
            {
                u2 = u.get_Item(j);
                info(u2.get_Title());
            }
            break; //sadece ilk sayfayı al ve çık (örnek dökümü hızlı almak için konuldu.)...
        }
    }
    catch(Exception::CLRError)
    {
        ex = ClrInterop::getLastException();
        if (ex != null)
        {
            ex = ex.get_InnerException();
            if (ex != null)
            {
                error(ex.ToString());
            }
        }

    }
}

Yukarıdaki örnek sisteme kayıtlı efatura kullanıcılarının listesini almak içindi. Diğer fonksiyonları da örnekten yararlanarak yapabilirsiniz.

Not: Sizin kodunuzda uyumAX.uyumServis yerine oluşturduğunuz referansa verdiğiniz isme göre farklı bir adres yazmanız gerekebilir.

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.

Forma aşağıdaki kodları ekleyin:

public class FormRun extends ObjectRun
{
    InventDimCtrl_Frm_EditDimensions        inventDimFormSetup;
}

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)); //InventDimDisplay is the datasource name.
            inventDimFormSetup.formSetControls( true);
            break;

        // Datasource Field change
        case InventDimFormDesignUpdate::FieldChange :
            inventDimFormSetup.formActiveSetup(InventDimGroupSetup::newItemId(SNBProductDemonte.ItemId)); //InventDimDisplay is the datasource name.
            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://community.dynamics.com/ax/b/daxbeginners/archive/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();