Search This Blog

Thursday, April 26, 2012

AX2012 Import PriceDiscount journals using PricePriceDiscJournalService


The following sample code used to create the agreement journals using PricePriceDiscJournalService.

static void Krishh_ImportPriceTradeAgreementJournals(Args _args)
{
    // variable declaration
    PricePriceDiscJournalService            PriceDiscSvc;
    PricePriceDiscJournal                   PriceDiscJour;
    PricePriceDiscJournal_PriceDiscAdmTrans PriceDiscJourAdmTrans;
    PricePriceDiscJournal_InventDim         PriceDiscJourDim;

    AifEntityKeyList                        keys;
 
    // Instantilization
    PriceDiscSvc = PricePriceDiscJournalService::construct();
    PriceDiscJour = new PricePriceDiscJournal();
    PriceDiscJourAdmTrans = PriceDiscJour.createPriceDiscAdmTrans().addNew();
    PriceDiscJourDim = PriceDiscJourAdmTrans.createInventDim().addNew();

    // Set PriceDiscJourDim by getting the invent Item from EcoResProduct
    PriceDiscJourDim.parminventDimId(InventDimCombination::
        findByDistinctProductVariant(
            EcoResProduct::findByDisplayProductNumber(
               "PT SKRUE WN 5451 K30").RecId)
                    .InventDimId);

    //PriceDiscJourAdmTrans
    //you can pass the field parameters based on the fields that available with you.'
    PriceDiscJourAdmTrans.parmInventDim().add(PriceDiscJourDim);
    PriceDiscJourAdmTrans.parmItemRelation("1-02-51400");
    PriceDiscJourAdmTrans.parmItemCode(TableGroupAll::Table);
    PriceDiscJourAdmTrans.parmAmount(98.00);
    PriceDiscJourAdmTrans.parmFromDate(today());
    PriceDiscJourAdmTrans.parmAccountCode(TableGroupAll::All);
    //define the purch prices or sales prices by defining the enum below
    PriceDiscJourAdmTrans.parmrelation(PriceType::PriceSales);
    // you can pass your own currency or you can get company standard currency
    PriceDiscJourAdmTrans.parmCurrency(CompanyInfo::standardCurrency());

    // creates the journal
    // open the Procurement and sourcing and inquires you can click on price discount agreement journals.
    // you can review the journal and post the journal.
    keys = PriceDiscSvc.create(PriceDiscJour);
}

Wednesday, April 25, 2012

AX2012 Standard Document Services List


Microsoft Dynamics AX contains many standard document services. Each service supports a particular business process. You can customize these standard documents or create custom documents that suit your individual business processes.

AX2012 Standard Document Services 



   
        

Tuesday, April 24, 2012

AX2012 AIF Register Custom Adapter

I have created a Custom adapter, I want to register this adapter to use in Inbound services.
So please open the AifInboundPort form and open the init Method you can see the following line of code where we will register the Adapters.

AifSetup::registerOutOfTheBoxAdapters();


So if you want to add the new custom adapter to the adapter list you have add to add as the following in the above line method.

Class AifSetup
static public void registerOutOfTheBoxAdapters()
{
    AifSetup::registerAdapter(classNum(AifWcfAdapter));
    AifSetup::registerAdapter(classNum(AifWcfNetTcpAdapter));
    AifSetup::registerAdapter(classNum(AifWcfHttpAdapter));
    AifSetup::registerAdapter(classNum(AifWcfMsmqAdapter));
    AifSetup::registerAdapter(classNum(AifFileSystemAdapter));
// My customer adapter registered
    AifSetup::registerAdapter(classNum(AifXMLTransformFileSystemAdapter));
}


In Ax2009 We have AIFAdapter form to register the custom adapters, but in AX2012 we dont have that form to register the adapter at configuration level.

Monday, April 23, 2012

AX2012 Export Ledger Balances to CSV Build Reference field lookup in Batch Dialog

The following sample code is used to build the Reference control in the BatchDialog.
for This Example I created the Query with the DataSource as  MainAccount and using this Query run for this dialog.
This File used to Export the export ledger balances to Excel.
Test considerations:
Export should be tried with date interval covering multiple months.
Test should included account and all dimensions used in account structure and advanced account structure
Balances should be validated -Verify that balances are express in company currency.


Class declaration

class UploadLedgerBalances extends RunBaseBatch
{
    QueryRun                    queryRun;
    DialogField                 dialogFromDate;
    DialogField                 dialogToDate;
    DialogField                 dialogFilename;
    DialogField                 dialogAccountStructureHierarchy;
    // Dialog
    DialogRunbase               dialog;
    DimensionHierarchyId        accountStructureHierarchy;
    #File
    TransDate                   fromDate,toDate;
    Filename                    filename;
    CommaTextIo         commaTextIo;
    FileIOPermission    permission;
    container  dimensionHeader,dimensionValues;

    #DEFINE.CurrentVersion(1)
     #LOCALMACRO.CurrentList
       fromDate,
       toDate,
       filename,
    accountStructureHierarchy
    #ENDMACRO
}


public void new()
{
    super();
    queryRun = new QueryRun(queryStr(OpexUpload));
}



public QueryRun queryRun()
{
    return queryRun;
}



public boolean showQueryValues()
{
    return true;
}


Override the Dialog method

public Object dialog()
{
    dialog = super();
    dialogFromDate  = dialog.addFieldValue(extendedTypeStr(TransDate), fromDate,  "@SYS24050");
    dialogToDate = dialog.addFieldValue(extendedTypeStr(TransDate), toDate,  "@SYS14656");
    dialogFilename = dialog.addFieldValue(extendedTypeStr(FilenameSave), filename, "@SYS16423");


    dialogAccountStructureHierarchy = dialog.addFieldValue(extendedTypeStr(DimensionHierarchyId),this.mainHierarchy() , "Account Structure");
    dialogAccountStructureHierarchy.registerOverrideMethod(methodstr(FormReferenceControl, lookupReference), methodstr(OpexUpload, lookupAccountReference), this);
    dialogAccountStructureHierarchy.registerOverrideMethod(methodstr(FormReferenceControl, resolveReference), methodstr(OpexUpload, resolveAccountReference), this);

    dialog.allowUpdateOnSelectCtrl(true);
    this.dialogSelectCtrl();
    return dialog;
}


public boolean getFromDialog()
{
    fromDate                          = dialogFromDate.value();
    toDate                            = dialogToDate.value();
    filename                          = dialogFilename.value();
    accountStructureHierarchy         = dialogAccountStructureHierarchy.value();
    return super();
}



public Common lookupAccountReference(FormReferenceControl _formReferenceControl)
{
    return DimensionHierarchy::LookupReference(_formReferenceControl);
}


public Common resolveAccountReference(FormReferenceControl _formReferenceControl)
{
    return DimensionHierarchy::ResolveReference(_formReferenceControl);
}




private DimensionHierarchyId mainHierarchy(DimensionHierarchyId _mainHierarchy =  accountStructureHierarchy)
{
    accountStructureHierarchy = _mainHierarchy;
    return  accountStructureHierarchy;
}

// DimensionHierarchy Table I create two methods as following which i used in the dialog class methods
public static Common LookupReference(FormReferenceControl _formReferenceControl)

{
    DimensionHierarchy      selectedRecord,
                            commonHierarchy;
    Query                   lookupQuery;
    QueryBuildDataSource    qbds;
    SysReferenceTableLookup sysTableLookup = SysReferenceTableLookup::newParameters(tableNum(DimensionHierarchy),
                                                                                    _formReferenceControl, true);

    // Do not call super as we're providing our own custom lookup logic.
    // selectedRecord = super(_formReferenceControl);

    // Display the Title and Department fields in the lookup form.
    sysTableLookup.addLookupfield(fieldNum(DimensionHierarchy, Name));
  //  sysTableLookup.addLookupfield(fieldNum(DimensionHierarchy, Description));

    // Create a custom Query that filters and displays just the person titles
    lookupQuery = new Query();
    qbds = lookupQuery.addDataSource(tableNum(DimensionHierarchy));
 //   qbds.addRange(fieldNum(DimensionHierarchy, StructureType)).value(queryValue(DimensionHierarchyType::Focus));
    qbds.addRange(fieldNum(DimensionHierarchy, DeletedVersion)).value(queryValue(0));
    qbds.addRange(fieldNum(DimensionHierarchy, IsSystemGenerated)).value(queryValue(NoYes::No));
    qbds.addRange(fieldNum(DimensionHierarchy, IsDraft)).value(queryValue(NoYes::No));
     // If a common focus is specify, filter to only show values that overlap

        // Add a range on value "0" to ensure that at least one range exists. Without
        // this dummy range at the beginning, if there are no hierarchies that apply
        // then no ranges will be added and the user would see all values by default.
        qbds.addRange(fieldNum(DimensionHierarchy, RecId)).value(queryValue(0));

        while select RecId from commonHierarchy where
            commonHierarchy.IsSystemGenerated == NoYes::No &&
            commonHierarchy.IsDraft           == NoYes::No &&
            commonHierarchy.DeletedVersion == 0
        {
           qbds.addRange(fieldNum(DimensionHierarchy, RecId)).value(queryValue(commonHierarchy.RecId));

        }
    sysTableLookup.parmQuery(lookupQuery);

    selectedRecord = sysTableLookup.performFormLookup();
    return selectedRecord;
}

// This method is used to resolve the reference Id based on the selected Account structure.

public static Common ResolveReference(FormReferenceControl _formReferenceControl)
{
    DimensionHierarchy  resolvedRecord;
    Name                hierarchyName;

    // Do not call super as we're providing our own disambiguation logic.
    // resolvedRecord = super();

    hierarchyName = _formReferenceControl.filterValue(AbsoluteFieldBinding::construct(fieldStr(DimensionHierarchy, Name), tableStr(DimensionHierarchy))).value();

    // Only search hierarchies
    select firstonly resolvedRecord where
        resolvedRecord.Name == hierarchyName &&
        resolvedRecord.IsSystemGenerated == NoYes::No &&
        resolvedRecord.IsDraft           == NoYes::No &&
        resolvedRecord.DeletedVersion == 0;

    return resolvedRecord;
}


/// <summary>
///    Contains the code that does the actual job of the class.
/// </summary>
public void run()
{
    MainAccount mainAccount;
    RefRecId ledgerDimensionRecid;
    DimensionAttributeValueCombination dimCombination;
    try
    {
        dimensionHeader=conNull();
        if (! this.validate())
        {
            return;
        }

        permission = new FileIOPermission(fileName,#io_append);
        permission.assert();
        commaTextIo = new CommaTextIo(fileName,#io_append);
        this.writeCommaIOHeader();
        while (queryRun.next())
        {
            mainAccount = queryRun.get(tableNum(MainAccount));
//If you want to get the Hierarchy based on the Main Account you  can uncomment the below line and used this recid in the while select.
//I am using the input from the user that we build on dialog.below bolded value is the selected from dialog.

          //  dimHierarchyRecid=DimensionHierarchy::getAccountStructure(mainAccount.RecId);
            while select  recid from dimCombination where  dimCombination.MainAccount==mainAccount.RecId
               && dimCombination.AccountStructure==accountStructureHierarchy
               && dimCombination.AccountStructure !=0
            {
                ledgerDimensionRecid=dimCombination.RecId;
                //gets the DimensionValues
                dimensionValues=conNull();
                this.getDimensionValues(ledgerDimensionRecid);

                this.getTransAmount(ledgerDimensionRecid,mainAccount.MainAccountId);
            }
        }
        CodeAccessPermission::revertAssert();
    }
    catch (Exception::Deadlock)
    {
        queryRun.reset();
        retry;
    }
}


// This method is used to get the active dimensions for the current entity -->
void getActiveFinancialDimensions()
{
    DimensionAttributeSetItem   dimAttrSetItem;
    DimensionAttribute          dimAttr;
    DimensionEnumeration        dimensionSetId;

    DimensionHierarchyLevel     dimHierarchyLevel;
    recId                       chartOfAccountsId;
    LedgerChartOfAccountsStructure  ledgerChartOfAccountsStructure;
    ;
    //Get the record Id (dimension set id) for current ledger to find active dimensions
    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();
    chartOfAccountsId = Ledger::find(Ledger::current()).ChartOfAccounts;

    //Find all the active dimensions for current ledger except main account and display them
    while select * from dimAttr
             where dimAttr.Type != DimensionAttributeType::MainAccount
        join RecId from dimAttrSetItem
            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&
                dimAttrSetItem.DimensionAttributeSet == dimensionSetId
        join RecId from dimHierarchyLevel
            order by level
            where dimHierarchyLevel.DimensionAttribute == dimAttr.RecId
         exists join ledgerChartOfAccountsStructure
            where ledgerChartOfAccountsStructure.DimensionHierarchy == dimHierarchyLevel.DimensionHierarchy &&
                  ledgerChartOfAccountsStructure.ChartOfAccounts == chartOfAccountsId
    {
        dimensionHeader +=dimAttr.Name;
    }
}

///  This method is used to get the dimension values for that ledger dimension-->

private void getDimensionValues(RefRecId _dimCombRecid)
{

    DimensionAttributeValueCombination  dimAttrValueComb;
    DimensionStorage        dimensionStorage;
    DimensionStorageSegment segment;
    int                     segmentCount, segmentIndex;
    int                     hierarchyCount, hierarchyIndex;

    SysDim                  segmentValue;
    ;

    dimAttrValueComb = DimensionAttributeValueCombination::find(_dimCombRecid);
    dimensionStorage = DimensionStorage::findById(dimAttrValueComb.RecId);
    if (dimensionStorage == null)
    {
        throw error("@SYS83964");
    }

    hierarchyCount = dimensionStorage.hierarchyCount();
    for(hierarchyIndex = 1; hierarchyIndex <= hierarchyCount; hierarchyIndex++)
    {
        segmentCount = dimensionStorage.segmentCountForHierarchy(hierarchyIndex);
        //Loop through segments and display required values
        for (segmentIndex = 2; segmentIndex <= segmentCount; segmentIndex++)
        {
                segment = dimensionStorage.getSegmentForHierarchy(hierarchyIndex, segmentIndex);
                //Get segment value (id of the dimension)
                segmentValue        = segment.parmDisplayValue();
                dimensionValues += segmentValue;
        }
    }
}


///  This method is used to sum of transaction amount for that fiscal period-->

private void getTransAmount(RefRecId  _dimensionRecid,MainAccountNum _mainAccount)
{
    GeneralJournalEntry  generalJournalEntry;
    GeneralJournalAccountEntry generalJournalAccountEntry;
    LedgerDimensionAccount  ledgerDimensionAccount;
    FiscalCalendarPeriod fiscalCalendarPeriod;
    int numofPeriods;
    TransDate fiscalNextPeriodDate;
    AmountCur   VoucherTransAmount;
    Boolean  voucherExits;
    ;
    ledgerDimensionAccount=_dimensionRecid;
    // gets the number of periods between start date and Todate
    numofPeriods=FiscalCalendars::numberOfPeriodsBetweenDates(CompanyInfo::fiscalCalendarRecId(),fromDate,toDate);
    fiscalNextPeriodDate=fromDate;

    while(numofPeriods>0)
    {
fiscalCalendarPeriod=FiscalCalendars::findPeriodByPeriodCodeDate(CompanyInfo::fiscalCalendarRecId(),fiscalNextPeriodDate);
        VoucherTransAmount=0;
        voucherExits=false;
        while select LedgerDimension,TransactionCurrencyAmount,TransactionCurrencyCode,AccountingCurrencyAmount from generalJournalAccountEntry
                where generalJournalAccountEntry.LedgerDimension==ledgerDimensionAccount
        join JournalNumber from generalJournalEntry
            where generalJournalEntry.RecId==generalJournalAccountEntry.GeneralJournalEntry
            && generalJournalEntry.FiscalCalendarPeriod==fiscalCalendarPeriod.RecId
        {
            // write the lines for the Ledger account  for that fiscal period
            if(generalJournalAccountEntry.TransactionCurrencyCode == CompanyInfo::standardCurrency())
            {
                VoucherTransAmount +=generalJournalAccountEntry.TransactionCurrencyAmount;
            }
            else
            {
                VoucherTransAmount += generalJournalAccountEntry.AccountingCurrencyAmount;
            }
            voucherExits=true;
        }
        if(voucherExits)
        {
            this.WriteCommaLines(fiscalCalendarPeriod.EndDate,_mainAccount,VoucherTransAmount);
        }
        fiscalNextPeriodDate=FiscalCalendars::findNextPeriod(CompanyInfo::fiscalCalendarRecId(),fiscalNextPeriodDate);
        numofPeriods=FiscalCalendars::numberOfPeriodsBetweenDates(CompanyInfo::fiscalCalendarRecId(),fiscalNextPeriodDate,toDate);
    }
}


The OutPut of File will look like as below

"Date","Account","Department","Organization","Customer","Item","Project","SAPSUBLedgeraccount","Amount"
"2012/03/31","100020","410","RSDK_OTO","X00179","1-02-51400","00179","105",7.44
"2012/02/29","100030","410","RSDK_OTO","X00179","","","",-22
"2012/03/31","100030","410","RSOTO_DBIZ","X00208","1-02-53200","0100","115",-7.44



When you run this class you can see the Dialog as follows






Ax2012 Replace financial Dimensions


This sample code is used to replace the Organization value based on the selection of department dimension.


Req:- Dimension Department inheritance.
when we select the department we have to select the default organization.


Before doing this sample, I build one form which will loads the Department and organization and user will select the department dimension and default organization for that department.
ex:-
Dept    organization
600     roskilds
650    kildemos




static DimensionAttributeValueCombination Krishh_ReplaceLedgerDimensions(LedgerDimensionAccount targetDimension)
{
    #LedgerSHA1Hash
    DimensionSHA1Hash               hash; //To store the calculated hash for DimensionAttributeValueSet
    HashKey                         valueKeyHashArray[]; //To store the has key of dimension in question
    Map                             dimAttrIdx, dimAttrRecId; //to store the dimension index and backing entity type
    DimensionAttributeSetItem       dimAttrSetItem; // Contains the number of dimensions active for a account structure ledger
    DimensionAttribute              dimAttr,dimAttrNew; // Contains the financial dimensions records
    DimensionAttributeValue         dimAttrValue; // Contains used financial dimension values
    DimensionAttributeValueSet      dimAttrValueSet; //Contains default dimension records
    DimensionAttributeValueSetItem  dimAttrValueSetItem; //Contains individual records for default dimensions
    DimensionEnumeration            dimensionSetId; //Record id for table that contains active dimensions for current ledger
   // LedgerDimensionAccount          targetDimension = 5637151382; //Record Id DimensionAttributeValueCombination table in which attribute value is to be replaced
    LedgerDimensionAccount          ledgerDimension; // To hold the resultant DimensionAttributeValueCombination record id
    LedgerDimensionAccount          mainAccDimension; // Record id for LedgerDimension(DimensionAttributeValueCombination) containing default account for main account RecId
    DimensionStorage                dimensionStorage; // Class Dimension storage is used to store and manipulate the values of combination
    DimensionStorageSegment         segment; // Class DimensionStorageSegment will get specfic segments based on hierarchies
    DimAttributeProjTable           dimAttributeProjTable;

    DimensionFinancialTag           financialTag;

    int     segmentCount, segmentIndex;
    int     hierarchyCount, hierarchyIndex;
    SysDim  segmentValue, mainAccountValue;
    int     dimAttrCount, i;
    int     OrgBackEntityType; //Stores the backing entity type for Employee type dimension
    str     valueStrArray[]; //To store the dimension attribute values
    int64   valueKeyArray[]; //To store the record ids of DimensionAtrributeValue table
    int     backingEntityInstance;

    str     segmentName;// get the segment name ex: get the Department
    Department departmentValue;
    Organisation organizatioValue;

    ;

    //The  backing entity will be Financial Tag
    OrgBackEntityType = tableNum(DimensionFinancialTag);

    //Initialize the map to store the backing entity types
    dimAttrIdx = new Map(Types::Integer, Types::Integer);
    dimAttrRecId = new Map(Types::Integer, Types::Int64);

    //Get the record Id (dimension set id) for current ledger to find active dimensions
    dimensionSetId = DimensionCache::getDimensionAttributeSetForLedger();

    //Find all the active dimensions for current ledger except main account and store there
    //backing entity type in the map
    while select * from dimAttr
            order by Name
            where dimAttr.Type != DimensionAttributeType::MainAccount
        join RecId from dimAttrSetItem
            where dimAttrSetItem.DimensionAttribute == dimAttr.RecId &&
                dimAttrSetItem.DimensionAttributeSet == dimensionSetId

    {
        dimAttrCount++;
        dimAttrIdx.insert(dimAttr.BackingEntityType, dimAttrCount);
        dimAttrRecId.insert(dimAttr.BackingEntityType, dimAttr.RecId);
    }

    //initialize hash key array to null
    for (i = 1; i<= dimAttrCount; i++)
    {
        valueKeyHashArray[i] = emptyGuid();
        valueStrArray[i] = '';
        valueKeyArray[i] = 0;
    }

    // Default hash key array with required dimension value
    // Get dimension storage
    dimensionStorage = DimensionStorage::findById(targetDimension);
    if (dimensionStorage == null)
    {
        throw error("@SYS83964");
    }

    // Get hierarchy count
    hierarchyCount = dimensionStorage.hierarchyCount();
    //Loop through hierarchies to get individual segments
    for(hierarchyIndex = 1; hierarchyIndex <= hierarchyCount; hierarchyIndex++)
    {
        //Get segment count for hierarchy
        segmentCount = dimensionStorage.segmentCountForHierarchy(hierarchyIndex);

        //Loop through segments and display required values
        for (segmentIndex = 1; segmentIndex <= segmentCount; segmentIndex++)
        {
            // Get segment
            segment = dimensionStorage.getSegmentForHierarchy(hierarchyIndex, segmentIndex);

            // Get the segment information
            if (segment.parmDimensionAttributeValueId() != 0)
            {

                //Get the backing entity type;
                backingEntityInstance = DimensionAttribute::find(DimensionAttributeValue::find(segment.parmDimensionAttributeValueId()).DimensionAttribute).BackingEntityType;
                segmentName = DimensionAttribute::find(DimensionAttributeValue::find(segment.parmDimensionAttributeValueId()).DimensionAttribute).Name;

                if (backingEntityInstance == tableNum(DimAttributeMainAccount))
                    mainAccountValue = segment.parmDisplayValue();

                if(segmentName=="Department")
                    departmentValue=segment.parmDisplayValue();

                if (dimAttrIdx.exists(backingEntityInstance))
                {
                    i = dimAttrIdx.lookup(backingEntityInstance);
                    valueKeyHashArray[i]    = segment.parmHashKey();
                    valueKeyArray[i]        = segment.parmDimensionAttributeValueId();
                    valueStrArray[i]        = segment.parmDisplayValue();
                }

            }
        }
    }

    //Find the Dimension attribute record for the dimension to work on, in our case it is HcmWorker
    dimAttr.clear();

    select firstonly
            dimAttrNew
        where
            dimAttrNew.Name=="Organization";
    dimAttr = dimAttrNew;


 // store the Organization value for the Department and loads the Organization based on the selection of department in the General Journal   organizatioValue=DefaultOrganisationValues::findbyDepartmentOrganizations(departmentValue).Organisation;

    select firstonly financialTag where financialTag.Value==organizatioValue;


    //Find the required Dimension Attribute Value record
    //Create if necessary
    dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndEntityInst(dimAttr.RecId, financialTag.RecId, false, true);

    //Replace the required combination hash keys and other value arrays
    i = dimAttrIdx.lookup(OrgBackEntityType);
    valueKeyHashArray[i]    = dimAttrValue.HashKey;
    valueStrArray[i]        = dimAttributeProjTable.Value;
    valueKeyArray[i]        = dimAttrValue.RecId;

    //Calculate the hash for the current values
    hash = DimensionAttributeValueSetStorage::getHashFromArray(valueKeyHashArray, dimAttrCount);

    //Null hash indicates no values exist, which may occur if the user entered an invalid value for one dimension attribute
    if (hash == conNull())
    {
        throw error("Wrong value for Organization Dimension");
    }

    // Search for existing value set
    dimAttrValueSet = DimensionAttributeValueSet::findByHash(hash);

   // This value set does not exist, so it must be persisted
    if (!dimAttrValueSet)
    {
        ttsbegin;

        // Insert the value set with appropriate hash
        dimAttrValueSet.Hash = hash;
        dimAttrValueSet.insert();

        // Insert only specified set items use this
        for (i = 1; i <= dimAttrCount; i++)
        {
            if (valueKeyArray[i] != 0)
            {
                dimAttrValueSetItem.clear();
                dimAttrValueSetItem.DimensionAttributeValueSet = dimAttrValueSet.RecId;
                dimAttrValueSetItem.DimensionAttributeValue = valueKeyArray[i];
                dimAttrValueSetItem.DisplayValue = valueStrArray[i];
                dimAttrValueSetItem.insert();
            }
        }
        ttsCommit;

    }

    // Get the default account for main account
    mainAccDimension = DimensionStorage::getDefaultAccountForMainAccountNum(mainAccountValue);

    //Find or create the LedgerDimension record for required combination
    ledgerDimension = DimensionDefaultingService::serviceCreateLedgerDimension(
                                                            mainAccDimension,
                                                            dimAttrValueSet.RecId);

   // info(strFmt("Original %1: %2", targetDimension, DimensionAttributeValueCombination::find(targetDimension).DisplayValue));
    //info(strFmt("Replaced %1: %2", ledgerDimension, DimensionAttributeValueCombination::find(ledgerDimension).DisplayValue));
    return DimensionAttributeValueCombination::find(ledgerDimension);
}


Wednesday, April 11, 2012

Ax2012 import Dimension financial Tag values from CSV

This job is used to import data into DimensionFinancialTag Table, before doing that first we have to get the record id of financial category that this financialTag values should be inserted.

static void krishh_ImportDimensionFinancialTagValues(Args _args)
{
    SysExcelApplication application;
    SysExcelWorkbooks workbooks;
    SysExcelWorkbook workbook;
    SysExcelWorksheets worksheets;
    SysExcelWorksheet worksheet;
    SysExcelCells cells;
    COMVariantType type;
    int row;
    filename  filename;

    str dimvalues;
    str           valuedescr;
    DimensionFinancialTag financialTag;
    RefRecId         categoryRecid;
    ;
    // FinancialCategory Record Recid
    categoryRecid=5637144826;
    filename=@"C:\TEMP\SAP_product_item.xlsx";
    application = SysExcelApplication::construct();
    workbooks = application.workbooks();
    row=1;

    try
    {
        workbooks.open(filename,0,true);
    }
    catch (Exception::Error)
    {
        throw error("@SYS19358");
    }
    workbook = workbooks.item(1);
    worksheets = workbook.worksheets();
    worksheet = worksheets.itemFromNum(1);
    cells = worksheet.cells();

    //Iterate through cells and get the values
    try
    {
    ttsBegin;
        do
        {
        //Incrementing the row line to next Row
        row++;

        dimvalues = num2str(cells.item(row, 1).value().double(),0,0,0,0);
        valuedescr = num2str(cells.item(row,2).value().double(),0,0,0,0);
        financialTag=DimensionFinancialTag::findByFinancialTagCategoryAndValue(categoryRecid,dimvalues,true);
        if(!financialTag)
        {
            financialTag.clear();
            financialTag.Description=valuedescr;
            financialTag.Value=dimvalues;
            financialTag.FinancialTagCategory=categoryRecid;
            financialTag.insert();
        }
        else
        {
            financialTag.Description=valuedescr;
            financialTag.Value=dimvalues;
            financialTag.FinancialTagCategory=categoryRecid;
            financialTag.skipTTSCheck(true);
            financialTag.update();
        }
        // Loads the next row into the variant type and validating that its is empty or not
        type = cells.item(row+1, 1).value().variantType();
        }
        while (type != COMVariantType::VT_EMPTY);
    ttsCommit;
    }
    catch(Exception::Error)
    {
        ttsAbort;
    }
    // quits the application

    application.DisplayAlerts(false); //dont prompt saving message
    application.quit();
    application = null;
}

Monday, April 2, 2012

AX2012 Create Employee or Worker using HCMWorkerImport Service


In my previous post I used to create the worker by inserting into table directly. In this example I am using HCMWorkerImport Service for create the employee from CSV file. Before using this code make sure to change the fields positions using your file. and make sure you service (HcmWorkerImportService) is active.

Before writing the code please see the query that used for service AxdHcmWorkerImport, how the datasources relations are mapped in query, same way we should add the data to the entity objects.



  private void  krishh_employeeCreateUsingService(container _c)
        {
            HcmWorkerImportService                      hcmWorkerImportService;
            HcmWorkerImport                             hcmWorkerImport;
            HcmWorkerImport_HcmWorker                   hcmWorkerImport_HcmWorker;
            HcmWorkerImport_DirPerson_DirPerson         hcmWorkerImport_DirPerson_DirPerson;
            HcmWorkerImport_HcmPersonPrivateDetails     hcmWorkerImport_HcmPersonPrivateDetails;
            HcmWorkerImport_DirPersonName               hcmWorkerImport_DirPersonName;
            HcmWorkerImport_DirPartyPostalAddressVie    hcmWorkerImport_DirPartyPostalAddressVie;
     
            HcmWorkerImport_HcmEmployment               hcmWorkerImport_HcmEmployment;
            HcmWorkerImport_HcmEmploymentDetail         hcmWorkerImport_HcmEmploymentDetail;
            HcmWorkerImport_HcmWorkerTitle              hcmWorkerImport_HcmWorkerTitle;
            ;
        // creating the service object
            hcmWorkerImportService          = HcmWorkerImportService::construct();
            hcmWorkerImport                 = new HcmWorkerImport();
     
            hcmWorkerImport_HcmWorker       = hcmWorkerImport.createHcmWorker().addNew();
            hcmWorkerImport_HcmWorker.parmPersonnelNumber(conpeek(_c, EmployeeNumber));
     
            hcmWorkerImport_DirPerson_DirPerson = hcmWorkerImport_HcmWorker.createDirPerson().addNew();
            hcmWorkerImport_DirPerson_DirPerson.parmInitials(conpeek(_c, Initials));
            hcmWorkerImport_DirPerson_DirPerson.parmProfessionalTitle(conpeek(_c, Position));
     
            hcmWorkerImport_DirPersonName       = hcmWorkerImport_DirPerson_DirPerson.createDirPersonName().addNew();
            hcmWorkerImport_DirPersonName.parmFirstName(conpeek(_c, FirstName));
            hcmWorkerImport_DirPersonName.parmMiddleName(conpeek(_c, MiddleName));
            hcmWorkerImport_DirPersonName.parmLastName(conpeek(_c, LastName));
     
            hcmWorkerImport_HcmPersonPrivateDetails = hcmWorkerImport_DirPerson_DirPerson.createHcmPersonPrivateDetails().addNew();
            hcmWorkerImport_HcmPersonPrivateDetails.parmBirthDate(HrmImportEmployeeMasterdata::convDate(conpeek(_c, BirthDate)));
     
            hcmWorkerImport_HcmPersonPrivateDetails.parmGender(HrmImportEmployeeMasterdata::convGender(conpeek(_c, Gender)));
     
            hcmWorkerImport_DirPartyPostalAddressVie = hcmWorkerImport_DirPerson_DirPerson.createDirPartyPostalAddressView().addNew();
            hcmWorkerImport_DirPartyPostalAddressVie.parmCountryRegionId(HrmImportEmployeeMasterdata::defaultCountryRegionId());
            hcmWorkerImport_DirPartyPostalAddressVie.parmRoles(HrmImportEmployeeMasterdata::defaultRole());
            hcmWorkerImport_DirPartyPostalAddressVie.parmStreet(conpeek(_c, Address));
          hcmWorkerImport_DirPartyPostalAddressVie.parmStreetNumber(conpeek(_c, streetnum)));
            hcmWorkerImport_DirPartyPostalAddressVie.parmZipCode(conpeek(_c, PostalCode));
     
            hcmWorkerImport_HcmEmployment   = hcmWorkerImport_HcmWorker.createHcmEmployment().addNew();
            hcmWorkerImport_HcmEmployment.parmLegalEntity(curext());
     
            hcmWorkerImport_HcmEmploymentDetail = hcmWorkerImport_HcmEmployment.createHcmEmploymentDetail().addNew();
            hcmWorkerImport_HcmEmploymentDetail.parmWorkerStartDate(
                datetobeginUtcDateTime(HrmImportEmployeeMasterdata::convDate(conpeek(_c, DateOfHiring)), DateTimeUtil::getUserPreferredTimeZone()));
     
            hcmWorkerImportService.create(hcmWorkerImport);
     
        }

Ax2012 Upgrade process from AX4.0 and AX5.0

Setup source(4.0 or 5.0) Environment

1.      Import the PreProcessing (databaseupgrade\xpo\UpgradeAX5.xpo) XPO, located in the installation CD folder and Un check "Import with ID values:"
2.      Open the PreProcessing Checklist "SysCheckList_PreUpgrade50" located in the AX50PreUpgradeFramework project.
3.      The Preprocessing Checklist appears, if your checklists has this @ABC123 instead of text, and then do this to get the missing label file. To apply the new label files in your AX4/5 machine (if you are working with preprocessing framework):
·         Copy the label file to the label folder in your AX4/2009 machine
·         Restart the AOS
·         Label folder in AX4/2009 is a sub folder under ...\Application\Appl\ where you can find *.ald files in it.
4.      Run through the PreProcessing Checklist Items to prepare the database for Upgrade
·         If upgrading AX 2009, and the upgrade scripts don't run after opening the cockpit, jump to step #12 and follow the steps there to setup the batch server (AX4 does not require setting up a batch server). Then come back to this point and continue.
·         If upgrading AX4, You need to compile the ReleaseUpdate* classes and the ReleaseUpdateCockpit form.
·         If upgrading AX4, when running the cockpit run multiple instances of AX4:
o   Start the new Microsoft Dynamics AX client.
o   Select Basic > Periodic > Batch > Processing. 
o   A batch dialog appears.
o   Add DataUpgrade in the Group field, and click OK.
5.      In the Inventory Dimension Group Upgrade checklist Item, click on the “Map dimension groups 1:1” button (Do not click on the “Assign identical groups” button) and then click on the “Set to Ready For Upgrade” button. 
6.      In the System Parameters checklist Item, select “en-us” as the default language and click on the “Set to Ready for Upgrade” button.
7.      In the Company Priority setup, click on the “Set to Ready for Upgrade” button.
8.      In the Product Upgrade Form, click on the Synchronize button and then on the Product Mapping -> Map all items 1:1. Click on the “Set to Ready for Upgrade” button after doing these steps.
9.      In the Units form, click on the “Automatically assignment” button.
a.       Set all decimals to 2
b.      Set all Unit classes to “Length”
c.       Click on the “Validate” button to make sure no errors are found
d.      Click on the “Set to Ready for Upgrade” button.
10.  In the Pre-Upgrade of Unit Conversions checklist item click on the Validate button and then on the “Set to Ready for Upgrade” button.
11.  In the Pre-Upgrade of Unit Texts click on the Validate button and then on the “Set to Ready for Upgrade” button.
12.  In the Pre-Upgrade Data checklist item you might need to configure the Batch Server and Batch Server Groups if the Live PreProcessing scripts don’t start running. In order to do so, go to Administration\Setup\Server Configuration
13.  Make sure that only the machine you are using has the Is Batch Server checkbox checked. Now go to the Batch Server Groups tab and select the DataUpdate Batch Server Group
14.  Another configuration that is required to start running these jobs is the Batch Group form. You can access this in Administration\Setup\Batch Groups
15.  Select the DataUpdate Batch Group and go to the Batch Servers tab.
16.  Make sure the machine you’re running the upgrade on is on the Selected Servers list on the left side pane.
17.  After running the Live PreUpgrade, continue with the next checklist items (Validate Pre Upgrade, check Single User Mode and Single User Mode Upgrade)
18.  Once the checklist is finished, the PreProcessing stage is done. Uninstall AX50 (don’t drop the database) and you are ready to go to the AX6 steps.

Starting an Upgrade from the Target Environment


1.      Install Dynamics AX 2012.
2.      Setup Ax 2012 pointing the AOS to a new Database . Specify a different database name for the Model Database. Make sure you select the "Register Database for Upgrade checkbox:"
3.      At this stage, you should have 3 databases in your system: Database
·         The AX50 PreProcessed database
·         The new AX6 database
·         The new AX2012 model database
4.      Start AX 2012 and run through the Upgrade checklist
5.      In the Provide License Information step, specify the license.
6.      At this point, the Target Environment upgrade process is started. Make your way through the first five checklist items. 

Data Upgrade Stages

Source DB connection step:
In the Source DB connection step, specify the server name where the Source Database is located and the Source Database name. Click OK once this information is entered.
PreSynchronize step:
This step loads the Upgrade cockpit. Depending on which stage you started the Upgrade Process; you might need to configure the Batch Groups and Batch Servers. Once this configuration is set, click the Run button. PreSync scripts should start running at this stage.
Create Tables Step:
This step synchronizes the database. No special steps need to be taken here.
Generate table and field mapping:
This step generates table and field mapping between source and target systems. There should be no mapping with error. 
Generate Bulk Copy and Script Prioritization Step:
Bulk Copy Priorities and Script-Table dependencies are resolved in this step. No special steps need to be taken here.
Launch Data Upgrade Step:
This step loads the Upgrade cockpit. Once the cockpit is loaded, click on the Run button and the Post Sync scripts should start running.
This is where the data is actually copied from the Source Database to the Target Database based on the Mappings found in the Generate Table and Field Mapping step.