Wednesday 9 February 2022

Ax 2012\D365 : Cheque creation code

                     Ax 2012\D365 : Cheque creation code 

public void createCheque(Args args)
    {
        LedgerJournalTrans                ledgerJournalTrans;
        BankAccountTable                   bankAccountTable;
        BankChequeTable                    bankChequeTable;
        DimensionAttributeValueCombination dimensionAttributeValueCombination;
        select  firstonly forupdate ledgerJournalTrans
            where ledgerJournalTrans.JournalNum == '12345' &&
                  ledgerJournalTrans.linenum    == 1;                                                                                                          ledgerJournalTrans.LineNum      == 1;
        if (ledgerJournalTrans.AmountCurDebit)
        {
            select firstonly DisplayValue
                from  dimensionAttributeValueCombination
                    where dimensionAttributeValueCombination.RecId == ledgerJournalTrans.LedgerDimension;
            bankChequeTable.clear();
            bankChequeTable.ChequeNum               =   ledgerJournalTrans.PLI_BankChequeNum;
            bankChequeTable.ChequeStatus            =   ChequeStatus::Payment;
            bankChequeTable.AccountID               =   bankAccountTable.AccountId;
            bankChequeTable.RecipientType           =   BankChequeRecipientType::Cust;
            bankChequeTable.AmountCur               =   ledgerJournalTrans.AmountCurDebit;
            bankChequeTable.BankCurrencyAmount      =   ledgerJournalTrans.AmountCurDebit;
            bankChequeTable.RecipientCompany        =   ledgerJournalTrans.Company;
            bankChequeTable.TransDate               =   staging.TransactionDate ;
            bankChequeTable.CurrencyCode            =   ledgerjournalTrans.CurrencyCode;
            bankChequeTable.BankCurrency            =   ledgerjournalTrans.CurrencyCode;
            bankChequeTable.RecipientAccountNum     =   dimensionAttributeValueCombination.DisplayValue;
            bankChequeTable.Voucher                 =   ledgerjournalTrans.Voucher;
            bankChequeTable.RecipientTransVoucher   =   ledgerjournalTrans.Voucher;
            bankChequeTable.SourceTableId           =   ledgerjournalTrans.TableId;
            bankChequeTable.SourceRecId             =   ledgerjournalTrans.RecId;
            if (BankChequeTable::exist(ledgerJournalTrans.PLI_BankChequeNum, ledgerjournalTrans.PLI_Account))
            {
                checkFailed(strfmt("@SYS24139", bankChequeTable.ChequeNum));
                throw error("@SYS18447");
            }
            bankChequeTable.insert();
            ttsbegin;
            ledgerJournalTrans.BankChequeNum = bankChequeTable.ChequeNum;
            ledgerjournalTrans.PaymentStatus = CustVendPaymStatus::Sent;
            ledgerJournalTrans.PaymReference = bankChequeTable.ChequeNum;
            ledgerJournalTrans.update();
            ttscommit;
        }
    }

Populate LedgerDimension value through code Ax 2012 & D365

Populate LedgerDimension value through code Ax 2012 & D365


public DimensionDynamicAccount getLedgerDimensionId(container _dimensionValue)
    {
        DimensionStorage        dimensionStorage = DimensionStorage::construct(0,      LedgerDimensionType::Account);
        DimensionAttributeValue dimAttributeValue;
        DimensionStorageSegment dimensionStorageSegment;
        DimensionHierarchyLevel dimHierarchyLevel;
        MainAccount             mainAccount;
        Recid                   dimHierarchyId;
        Recid                   mainAccountRecId;
        DimensionValue          dimensionValue;
        container               dimensions;

        for(int i = 1; i<= conLen(_dimensionValue); i++)
        {
            try
            {              
                    // Rest of dimensions
                    if(dimensionValue)
                    {
                        dimAttributeValue = DimensionAttributeValue::findByDimensionAttributeAndValueNoError(DimensionAttribute::findByName(conPeek(dimensions, i)), dimensionValue, false, true);
                        if (!dimAttributeValue)
                        {
                            // @JAT:DimensionNotFound = The value '%1' of the dimension '%2' does not exist.
                            throw error(strFmt("DimensionNotFound", dimensionValue, conPeek(dimensions, i)));
                        }
                        dimensionStorageSegment = DimensionStorageSegment::constructFromValue(dimAttributeValue.CachedDisplayValue, dimAttributeValue);
                        dimensionStorage.setSegment(i, dimensionStorageSegment);
                    }
                    else
                    {
                        dimensionStorageSegment = DimensionStorageSegment::emptySegment();
                        dimensionStorage.setSegment(i, dimensionStorageSegment);
                    }
                }
            
            catch
            {
                return 0;
            }
        }
        return dimensionStorage.save();
    }

Monday 11 January 2021

X++ code to generate ledger voucher number sequence in AX 2012 & D365

 

X++ code to generate ledger voucher number sequence in AX 2012 & D365


NumberSeq numberSeq;
NumberSequenceTable numSeqTable;
Voucher voucher;

select firstOnly numSeqTable
where numSeqTable.RecId == LedgerJournalName::find(ledgerJournalTable.JournalName).NumberSequenceTable;
if (numSeqTable && !voucher)
{
numberseq = numberseq::newGetVoucherFromCode(numSeqTable.NumberSequence);
voucher = numberseq.voucher();
}

ledgerJournalTrans.Voucher = voucher;

Thanks & Regards
Sindhu

Saturday 2 January 2021

Create Ledger Dimension through Code (x++)

          Create Ledger Dimension through Code (x++)


Microsoft has provided a service class which has a method provided  internally that merges the default dimension and the ledger account that you require.
This works only when you have default dimension & ledgerAccount that you want to merge .


LedgerDimension = DimensionDerivationDistributionRule::buildLedgerDimension(ledgerDimension,DefaultDimension);


Here the parameter Default dimension is the recid contains combination of your dimension values.
LedgerDimension is the LedgerMainAccount that is defaulted when you creating journals.


P.S : Default dimension creation code is provided in my another blog which return the RecId needed as aa parameter 'DefaultDimension' for the method buildLedgerDimension() in the above one liner code.

Blog for default dimension creation code : 

https://sbdynaax.blogspot.com/2021/01/c-reate-default-dimension-with-set-of.html

Thanks & Regards

Sindhu

Create Default Dimension with a set of dimension values through Code (x++)

 

      Create Default Dimension with a set of dimension values through Code (x++)


Below job specifies set of dimension values and get the default dimension(Recid) for that combination of the values passed.

static void getDefaultDimension(Args _args)
{
DimensionAttributeValueSetStorage valueSetStorage = new DimensionAttributeValueSetStorage();
DimensionDefault result;

int i;
DimensionAttribute dimensionAttribute;
DimensionAttributeValue dimensionAttributeValue;
container conAttr = [“Department”,”CostCentre” ,”ExpensePurpose”];
container conValue = [“00000030”, “OU_4574”, “Conference/Seminar”];
str dimValue;

for (i = 1; i <= conLen(conAttr); i++)
{
dimensionAttribute = dimensionAttribute::findByName(conPeek(conAttr,i));

if (dimensionAttribute.RecId == 0)
{
continue;
}

dimValue = conPeek(conValue,i);

if (dimValue != "")
{
// The last parameter is "true". A dimensionAttributeValue record will be created if not found.
dimensionAttributeValue =
dimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute,dimValue,false,true);

// Add the dimensionAttibuteValue to the default dimension
valueSetStorage.addItem(dimensionAttributeValue);
}
}

result = valueSetStorage.save();

}


Thanks & Regards

Sindhu

Thursday 24 December 2020

D365 F&O Import Data entity: postTargetProcess, copyCustomStagingToTarget

 D365 F&O Import Data entity: postTargetProcess, copyCustomStagingToTarget methods not called 

No row processing is achieved by enabling "Set-based processing = True"  and is used to imports records really fast.

Data management workspace > Data entities button

set-based

But when you really want to write some "postprocessing" logic, with the above setting the methods "postTargetProcess()", "copyCustomStagingToTarget()" are not called. Data entity with "Set-based processing" = false, calls "postTargetProcess( )"  and "copyCustomStagingToTarget()" method . 

One way  to run  postTargetProcess() code after importing all records with "Set-based processing" = true on  data entity is using post handlers.

[PostHandlerFor(classStr(DmfEntityWriter), methodStr(DmfEntityWriter, write))]

   public static void DmfEntityWriter_Post_write(XppPrePostArgs args)

   {

       DMFDefinitionGroupExecution  _dmfDefinitionGroupExecution = args.getArg('_definitionGroupExecution');

       // come code to iterate target table records exists joined from staging

   }

This method is called for all staging records where TransferStatus::Completed.

As this post hadler method is from the DMF base class DmfEntityWriter, it will be called for all entites.Hence we need to be careful while using this method and handle the logic for different entities with switch case as below.

str callerEntity = dmfDefinitionGroupExecution.EntityXMLName;

              switch (callerEntity)
              {

case 'CustCustomersV3Entity':

// something

break;

}

Thanks & Regards
Sindhu

D365 F&O Data Entity : DMF Methods calling sequence

 D365 F&O Data Entity : DMF Methods calling sequence






Thanks & Regards

Sindhu