Friday, June 22, 2018

Create and Post Project Expense journal in Dynamics 365 finance and operation

class Job_CreatePostProjExpJournalLines
{      
    /// <summary>
    /// Runs the class with the specified arguments.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    { 
        LedgerJournalName ledgerJournalName;
        LedgerJournalTable ledgerJournalTable;
        LedgerJournalTrans ledgerJournalTrans;
        LedgerJournalTrans_Project ledgerJournalTrans_Project;
        NumberSequenceTable numberSequenceTable;
        ledgerJournalCheckPost ledgerJournalCheckPost;
        ProjLinePropertySetup projLinePropertySetup;
        DirPersonUser personUser;
        HcmWorker worker;
        boolean priceFound = false;
        CostPrice costPriceMST;
        ProjPostCostJournal projPostCostJournal;
        ResourceView resourceView;
        NumberSeq numberseq;
        Amount amount = 753.00;
        boolean result = false;
        TransDate invoiceDate = mkdate(22,06,2018);
        ttsbegin;
        ledgerJournalName = LedgerJournalName::find("PrjJrn");
        if(ledgerJournalName)
        {
            ledgerJournalTable.JournalName = ledgerJournalName.JournalName;
            ledgerJournalTable.initFromLedgerJournalName();
            ledgerJournalTable.JournalNum = JournalTableData::newTable(ledgerJournalTable).nextJournalId();
            ledgerJournalTable.Name = ledgerJournalName.Name + "Sangeet";
            ledgerJournalTable.JournalType = LedgerJournalType::Cost;
            ledgerJournalTable.insert();
            if(ledgerJournalTable)
            {
                select NumberSequence from numberSequenceTable
                    where NumberSequenceTable.RecId == ledgerJournalName.NumberSequenceTable;
                numberseq = NumberSeq::NewGetVoucherFromCode(numberSequenceTable.NumberSequence);
                ledgerJournalTrans.initValue();
                ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum;
                ledgerJournalTrans.Voucher = numberseq.voucher();
                ledgerJournalTrans.TransDate = mkdate(22,06,2018);
                ledgerJournalTrans.Qty = 1;
                ledgerJournalTrans.AccountType = LedgerJournalACType::Project;
                ledgerJournalTrans.OffsetAccountType = LedgerJournalACType::Vend;
                ledgerJournalTrans.parmOffsetAccount("1011",ledgerJournalTrans.OffsetAccountType);
                ledgerJournalTrans.TransactionType = LedgerTransType::Payment;
                ledgerJournalTrans.CurrencyCode = "USD";
                ledgerJournalTrans.Invoice = "INV_0011";
                ledgerJournalTrans.Txt = strFmt("Expense Journal Auto Create");
                ledgerJournalTrans.Approved = NoYes::Yes;
                if(amount> 0)
                {
                    ledgerJournalTrans.AmountCurDebit = amount;
                }
                else
                {
                    ledgerJournalTrans.AmountCurCredit = abs(amount);
                }
                ledgerJournalTrans.Company = strUpr(curExt());
                ledgerJournalTrans.OffsetCompany = strUpr(curExt());
                select firstonly personUser where personUser.User == curUserId()
                    join worker
                    where worker.Person == personUser.PersonParty;
                ledgerJournalTrans.Approver = worker.RecId;
                ledgerJournalTrans.PostingProfile = 'GEN';
                ledgerJournalTrans.parmAccount("000004",ledgerJournalTrans.AccountType);
                ledgerJournalTrans.insert();
                if(ledgerJournalTrans)
                {
                    ledgerJournalTrans_Project.initValue();
                    ledgerJournalTrans_Project.CategoryId = "Cat1";
                    ledgerJournalTrans_Project.Qty = 1;
                    ledgerJournalTrans_Project.SalesCurrencyId = ledgerJournalTrans.CurrencyCode;
                    ledgerJournalTrans_Project.LinePropertyId = "Billable";
                    ledgerJournalTrans_Project.ProjTransDate = invoiceDate;
                    select resourceView
                        where resourceView.ResourceCompanyId == curExt();
                    ledgerJournalTrans_Project.Resource = resourceView.RecId;
                    ledgerJournalTrans_Project.ProjId = "000004";
                    ledgerJournalTrans_Project.RefRecId = ledgerJournalTrans.RecId;
                    ledgerJournalTrans_Project.Worker = ledgerJournalTrans.Approver;
                    ledgerJournalTrans_Project.CostPrice = amount;
                    costPriceMST = ProjCostSalesPrice::costPrice(ledgerJournalTrans, ledgerJournalTrans_Project, false);
                    [ledgerJournalTrans_Project.SalesPrice, priceFound] = ProjCostSalesPrice::findCostSalesPrice(ledgerJournalTrans_Project.ProjId,
                        ledgerJournalTrans_Project.Resource,
                        ledgerJournalTrans_Project.CategoryId,
                        costPriceMST,
                        CompanyInfoHelper::standardCurrency(),
                        ledgerJournalTrans_Project.SalesCurrencyId,
                        ledgerJournalTrans_Project.ProjTransDate,
                        ledgerJournalTrans_Project.ProjPriceGroupID,
                        false);
                    ledgerJournalTrans_Project.insert();
                    result = true;
                }
            }
        }
        ttscommit;
        if(result == true)
        {
            ledgerJournalCheckPost = ledgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable,NoYes::Yes);
            ledgerJournalCheckPost.run();
            info(Strfmt("Project Expense journal posted successfully %1 in %2", ledgerJournalTable.JournalNum,curext()));
        }
    }


}

Friday, June 15, 2018

Error: The text for the following task was not found: 0x0000 , 0x0135 , This could be due to an error or an outdated version of the kernel text file.


Issue: AX 2012 R2 and AX 2012 R3 installed in same machine, you may encountered this error while opening AX application

Error:

The text for the following task was not found:
0x0000 , 0x0135
This could be due to an error or an outdated version of the kernel text file.

Analysis: This error will occurs only if the default path (C:\ProgramFiles(x86)\Microsoft Dynamics AX\60\Client\Bin) you have an AX 2012 R2 client installed. Then the AX 2012 R3 client might use the R2 ktd-files.

Resolution:
  • Navigate to C:\ProgramFiles(x86)\Microsoft Dynamics AX\60\Client\Bin\AxSysEn-US.ktd in a text editor - it will be the R2 ktd-file. (Note: Default language file)
  • Find ">MSGID_TASKTEXTS5" 
  • After "0x1231 DropDialog" add this below following line and save the changes
  • New Line: 0x0135 Microsoft Dynamics Lifecycle Services | Microsoft Dynamics Lifecycle Services
File:

Thursday, June 14, 2018

Filter Default Dimension values through Query in AX 2012/D365

//Method
public void filterQueryByDimension(Query  _query,DataSourceName  _dataSourceName,FieldName   _fieldName)
{
    DimensionProvider   dimensionProvider = new DimensionProvider();
   
    void addDimFilter(Notes _rangeValue,Name  _dimensionName)
    {
        if (_rangeValue)
        {
            dimensionProvider.addAttributeRangeToQuery( _query,
                                                        _dataSourceName,
                                                        _fieldName,
                                                        DimensionComponent::DimensionAttribute,
                                                        _rangeValue,
                                                        _dimensionName);
        }
    }
    dimensionProvider.clearDimensionRangesFromQuery(_query);
       
    addDimFilter("<Dimension values from Contract Paramter>", "BusinessUnit");
    addDimFilter("<Dimension values from Contract Paramter>", "CostCenter");
    addDimFilter("<Dimension values from Contract Paramter>", "Department"); 
}

//Job (tested)
static void SAN_FilterDimensionTestJob(Args _args)
{
    Query                   query = new Query();
    QueryBuildDataSource    qbds;
    QueryRun                qr;
    SalesTable              salesTable;
   
    //Functions
    void addDimFilter(
                        DimensionProvider       _dimensionProvider,
                        Notes                   _rangeValue,
                        Name                    _dimensionName,
                        Query                   _query,
                        DataSourceName          _dataSourceName,
                        FieldName               _fieldName)
    {
        if (_rangeValue)
        {
            _dimensionProvider.addAttributeRangeToQuery( _query,
                                                        _dataSourceName,
                                                        _fieldName,
                                                        DimensionComponent::DimensionAttribute,
                                                        _rangeValue,
                                                        _dimensionName);
        }
    }   
    void filterQueryByDimension(
                                Query           _query,
                                DataSourceName  _dataSourceName,
                                FieldName       _fieldName)
    {
        DimensionProvider   dimensionProvider = new DimensionProvider();
       
        ;
        dimensionProvider.clearDimensionRangesFromQuery(_query);
       
        //addDimFilter(dimensionProvider,"<Dimension values from Contract Paramter>", "BusinessUnit",_query,_dataSourceName,_fieldName);
        //addDimFilter(dimensionProvider,"<Dimension values from Contract Paramter>", "CostCenter",_query,_dataSourceName,_fieldName);
        //addDimFilter(dimensionProvider,"<Dimension values from Contract Paramter>", "Department",_query,_dataSourceName,_fieldName); 
    }
    ;
    qbds = query.addDataSource(tableNum(SalesTable));
   
    filterQueryByDimension(query,qbds.name(),fieldStr(SalesTable, DefaultDimension));
   
    qr = new QueryRun(query);
   
    while (qr.next())
    {
        salesTable = qr.get(tableNum(SalesTable));
       
        info(salesTable.SalesId);
    }
}

Friday, June 8, 2018

Updating Hour journal Indirect Sales Price in to Project funding limit spent in AX 2012


Issue:
System is not updating Hour journal IndirectCost component Sales Price in to Project funding limit spent in AX 2012

Code Fix: (write logic to update Project funding limit Spent)_
AOTàClassà
PsaProjPostEmplIndirectJournalàMethod(ClasscreateAndUpdateTrans)

IDE MORPHX - Access only on Code Read and Debug in AX 2012

Access Restriction on Morphx IDE Development Environment in AX 2012

There is one option to remove the X++ development license from the environment. But doing that means that nobody will be able to even view the code

In this Development, User can able to only Read and Debug the code, will not able to do Create/Update/Delete objects. Even if user having system administrator rights.

Development:
Steps:
·         Add New Enum element --> SysVersionControlType
·         Create New Class --> SANRestrictAXDevAccess extends SysVersionControlSystem
o   Construct Method for new class
o   Override methods
      (Note: Copy below method from class "SysVersionControlSystem" and return code as Below)
Code: return false;
§  allowDelete
§  allowCreate
§  allowEdit
§  allowMoveToModel
§  allowRename
§  isTmpItemOpenedForDelete
                        Codereturn true;
§  applyGlobalSettings
§  ideIntegration   
·         Go to Class--> SysVersionControlSystem --> Method (NewType)
Add your new class (SANRestrictAXDevAccess), construct method in Switch case

Setup Changes Requires:
·         AX--> Development Workspace-->Version Control--> Version control Parameters
·         Select new created enum element from version control type list
·         And Version Control status should be enable

Error on Data Entity General Journals Import in Dynamics 365 for finance and operations

Issue/Cause:

1.      In Data Entities, System is inserting GL journal lines without creating reference in header line. In import document (excel or CSV) input for journal name is invalid with master Journal Names setup. 

Resolution: (Code Fix) .BUG
Adding separate new validation method to validate journal Names (validateJournalName).

In default Method (copyCustomStagingToTarget) in LedgerJournalEntity, adding newly added validation method in to it.

Note: 
Overlay requires (Not recommended)
Contact MS support or else wait for until MS releasing this code bug fix

Code: 
//Add new method in LedgerJournalEntity
//Added by Sangeeth - start
private static void validateJournalName(DMFDefinitionGroupExecution _dmfDefinitionGroupExecution, DMFStagingValidationLog _log)
    {
        // Put any rows that are not in Ledger journal name into error state
        LedgerJournalName ledgerJournalName;
        LedgerJournalEntityStaging staging;

        LedgerJournalEntityLog entityLog;
       
        ErrorMsg error = "Journal Name is invalid";

        insert_recordset entityLog (LedgerJournalEntityRecId, ErrorMessage)
            select RecId, error from staging
            where staging.DefinitionGroup == _dmfDefinitionGroupExecution.DefinitionGroup
               && staging.ExecutionId == _dmfDefinitionGroupExecution.ExecutionId
               && staging.TransferStatus == DMFTransferStatus::NotStarted
            exists join ledgerJournalName
                where staging.JournalName != ledgerJournalName.JournalName;


        // write errors to DMF validation log
        update_recordset staging
            setting TransferStatus = DMFTransferStatus::Error
        exists join entityLog
            where staging.RecId == entityLog.LedgerJournalEntityRecId;

        FieldName fieldName = fieldStr(LedgerJournalEntityStaging, JournalName);
        TableName tableName = tableStr(LedgerJournalEntityStaging);
        TableName entityName = "@GeneralLedger:LedgerJournalEntityLabel";
        DMFSourceTarget sourceTarget = DMFSourceTarget::Target;

        insert_recordset _log (DefinitionGroupName, ExecutionId, StagingRecId, StagingTableName, StagingColumnName, SourceTarget, EntityName, ErrorMessage)
            select DefinitionGroup, ExecutionId, RecId, tableName, fieldName, sourceTarget, entityName from staging
        join ErrorMessage from entityLog
            where staging.RecId == entityLog.LedgerJournalEntityRecId;
    }

//Added by Sangeeth - End

//Add below code to validate in
method: copyCustomStagingToTarget

  
//Old code
LedgerJournalEntity::validateJournalType(_dmfDefinitionGroupExecution, log);
LedgerJournalEntity::validateAndUpdateExchangeRates(_dmfDefinitionGroupExecution, log);
LedgerJournalEntity::validateAccountTypes(_dmfDefinitionGroupExecution, log);

  
//Replace by
LedgerJournalEntity::validateJournalName(_dmfDefinitionGroupExecution, log);
LedgerJournalEntity::validateJournalType(_dmfDefinitionGroupExecution, log);
LedgerJournalEntity::validateAndUpdateExchangeRates(_dmfDefinitionGroupExecution, log);

LedgerJournalEntity::validateAccountTypes(_dmfDefinitionGroupExecution, log); 

Convert Call stack to readable format in D365FO X++

//Input --container _xppCallStack = xSession::xppCallStack();  Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFr...