Thursday, September 30, 2021

how to get the count of repeated characters from a string in d365FO using x++

 Get the count of repeated characters from a string a string value.


    static void repeatedCharecters(Args _args) { str subTextPrev,subTextAll,subText,subTextOne,text = "AAAABBBCCDDDDDDDDDRRRRSSSSTTTTTTAAAAAA"; int i,j,k; ; for (i = 1 ; i <= strLen(text) ; i++) { subText = subStr(text, i, 1); k = 0; for (j = 1 ; j <= strLen(text) ; j++) { subTextOne = subStr(text, j, 1); if (subTextOne == subText) { k++; } } if (!strFind(subTextAll, subText, 1, strLen(text))) { subTextAll += subText + int2Str(k) + "\n"; } } info(subTextAll); }


Keep Daxing!!

Tuesday, September 28, 2021

Try and catch in d365FO

 

Code:

        #OCCRetryCount

    System.Exception ex;
try { } catch (Exception::Deadlock) { retry; } catch (Exception::UpdateConflict) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= #RetryNum) { throw Exception::UpdateConflictNotRecovered; } else { retry; } } else { throw Exception::UpdateConflict; } }     catch  { ex = CLRInterop::getLastException().GetBaseException(); error(ex.get_Message()); } ===========================OR====================================== try { // your code. }     catch (ex) { System.Exception e = ex; while (e != null) { errorMessage += e.Message; e = e.InnerException; } if (appl.ttsLevel() > 0) { ttsabort; } checkFailed("Process failed"); error(errorMessage); } catch (Exception::Deadlock) { continue; } catch (Exception::Error) { continue; } catch (Exception::Warning) { CLRInterop::getLastException(); continue; } catch (Exception::CLRError) { CLRInterop::getLastException(); continue; } -----------------------OR---------------------------------------------------------------             try { this.createRecord(); } catch (Exception::Deadlock) { retry; } catch (Exception::UpdateConflict) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= #RetryNum) { throw Exception::UpdateConflictNotRecovered; } else { retry; } } else { throw Exception::UpdateConflict; } } catch(Exception::DuplicateKeyException) { if (appl.ttsLevel() == 0) { if (xSession::currentRetryCount() >= #RetryNum) { throw Exception::DuplicateKeyExceptionNotRecovered; } else { retry; } } else { throw Exception::DuplicateKeyException; } } catch (Exception::Error) { // infolog.add(Exception::Error, strFmt("", SalesId)); continue; } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); Infolog.add(Exception::CLRError, ex.ToString()); continue; }
---------------------------OR----------------------------------------

With Retry: 

   System.Exception ex; try { } catch (ex) {     if (ex.Message == "Unauthorized401 error" && xSession::currentRetryCount() <= 2)     { // refreshing the token new ServiceClass().processOperation(); retry;     }     if (ex is System.Net.WebException)     { webResponse = (ex as System.Net.WebException).Response;     }     else     {      throw ex;     }     if (webResponse == null)     { throw new System.Exception("UnhandledErrorOccurredDuringTheHttpRequest");     } }

------------------------OR-----------------------------------------------------

With Finallay: 
    while generating reports catch will not trigger. So I have used finally it to fetch the error.

        System.Exception ex; boolean isSuccess; try { //your code isSuccess = true; } catch (ex) { isSuccess = true;     ex = CLRInterop::getLastException().GetBaseException();     throw Global::error(ex.get_Message()); } finally { if (isSuccess == false) { ex = CLRInterop::getLastException().GetBaseException(); Global::error(ex.get_Message()); } }

       Keep daxing!!

Monday, September 27, 2021

Add InventLocationId Lookup based on site in D365Fo.

 I got a requirement like I want to filter the warehouse based on site. Here I have to show standard lookup. So I follow the standard code. It is already written in purchTable.


 location field:

    class InventLocationId { public void lookup(FormControl _formControl, str _filterStr) { if (purchTable.InventSiteId) { InventLocation::lookupBySiteIdAllTypes(_formControl, purchTable.InventSiteId); } } } //lookupBySiteIdAllTypes method from inventLocation table. public static void lookupBySiteIdAllTypes(FormStringControl _ctrl, InventSiteId _inventSiteId) { SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum(InventLocation), _ctrl); ListEnumerator listEnumerator = List::create(InventLocation::standardLookupFields()).getEnumerator(); while (listEnumerator.moveNext()) { sysTableLookup.addLookupfield(fieldName2id(tableNum(InventLocation), listEnumerator.current())); } sysTableLookup.parmQuery(InventLocation::standardLookupBySiteIdQuery(_inventSiteId)); sysTableLookup.performFormLookup(); } //standardLookupFields method from InventLoaction table. Here we get the field from autoLookup group from table. public static container standardLookupFields() { List list = new List(Types::String); SysDictFieldGroup sysDictFieldGroup = new SysDictFieldGroup(tableNum(InventLocation), tableFieldgroupStr(InventLocation, AutoLookup)); Counter numberOfFields = sysDictFieldGroup.numberOfFields(); Counter i; for (i=1; i<=numberOfFields; i++) { list.addEnd(fieldId2name(tableNum(InventLocation),sysDictFieldGroup.field(i))); } return list.pack(); } //standardLookupBySiteIdQuery method is used to filer the query based on site. public static Query standardLookupBySiteIdQuery(InventSiteId _inventSiteId) { Query query = new Query(); QueryBuildDataSource queryBuildDataSource; queryBuildDataSource = query.addDataSource(tableNum(InventLocation)); if (_inventSiteId) { queryBuildDataSource.addRange(fieldNum(InventLocation,InventSiteId)).value(_inventSiteId); } return query; }


Keep daxing!!

Wednesday, September 22, 2021

Modify contract class in controller in D365fo.

I got a requirement to send the details of caller table recid and tableId to contract class. I done by using

prePromptModifyContract() method. By using this method we can change report design based on user inputs.

class SalesInvoicePrintController extends SrsReportRunController

{

    SalesInvoicePrintContract   contract;

     protected void prePromptModifyContract()

    {

        RecId               recId;

        LedgerJournalTrans  journalTrans;

        InventTransferJour  inventTransferJour;

        CustInvoiceTable    custInvoiceTable;

         contract      = this.parmReportContract().parmRdpContract();

         if(this.parmargs().dataset() == tableNum(LedgerJournalTrans))

        {

            journalTrans  = this.parmargs().record();

            recId         = journalTrans.RecId;

            contract.parmRecId(recId);

            contract.parmTableId(tableNum(LedgerJournalTrans));

        }

            //controller.getDataContractObject()//// for sys operation     //controller.parmReportContract().parmRdpContract()

}


Keep Daxing !!

Tuesday, September 21, 2021

SQL Query to get Security roles, duties and privileges in D365FO

  • All security roles 

            Select Name as SecurityRoleName FROM SecurityRole;

  • All security roles to duties
    SELECT SECURITYROLE.Name as SecurityRole, SECURITYDUTY.NAME as Duty FROM SECURITYOBJECTCHILDREREFERENCES JOIN SECURITYROLE ON SECURITYOBJECTCHILDREREFERENCES.IDENTIFIER = SECURITYROLE.AOTNAME JOIN SECURITYDUTY ON SECURITYOBJECTCHILDREREFERENCES.CHILDIDENTIFIER = SECURITYDUTY.IDENTIFIER     WHERE SECURITYOBJECTCHILDREREFERENCES.OBJECTTYPE = 0 AND SECURITYOBJECTCHILDREREFERENCES.CHILDOBJECTTYPE = 1

order by SECURITYROLE.Name asc;

  • All security roles with privileges 
    SELECT SECURITYROLE.Name as SecurityRole, SECURITYPRIVILEGE.NAME as Privileges FROM SECURITYOBJECTCHILDREREFERENCES JOIN SECURITYROLE ON SECURITYOBJECTCHILDREREFERENCES.IDENTIFIER = SECURITYROLE.AOTNAME JOIN SECURITYPRIVILEGE
        ON SECURITYOBJECTCHILDREREFERENCES.CHILDIDENTIFIER = SECURITYPRIVILEGE.IDENTIFIER WHERE SECURITYOBJECTCHILDREREFERENCES.OBJECTTYPE = 0 AND SECURITYOBJECTCHILDREREFERENCES.CHILDOBJECTTYPE = 2 order by SECURITYROLE.Name asc;

 

  • All role-duty combination with privilege 
SELECT SECURITYROLE.Name as SecurityRole, SECURITYROLE.AOTNAME as RoleSystemName,     SECURITYDUTY.NAME AS Duty, SECURITYDUTY.IDENTIFIER as DutySystemName,     SECURITYPRIVILEGE.NAME as Privilege, SECURITYPRIVILEGE.IDENTIFIER as PrivilegeSystemName FROM SECURITYOBJECTCHILDREREFERENCES JOIN SECURITYROLE ON SECURITYOBJECTCHILDREREFERENCES.IDENTIFIER = SECURITYROLE.AOTNAME JOIN SECURITYDUTY ON SECURITYOBJECTCHILDREREFERENCES.CHILDIDENTIFIER = SECURITYDUTY.IDENTIFIER JOIN SECURITYOBJECTCHILDREREFERENCES Table1 on Table1.IDENTIFIER = SECURITYDUTY.IDENTIFIER JOIN SECURITYPRIVILEGE on Table1.CHILDIDENTIFIER = SECURITYPRIVILEGE.IDENTIFIER WHERE SECURITYOBJECTCHILDREREFERENCES.OBJECTTYPE = 0 AND SECURITYOBJECTCHILDREREFERENCES.CHILDOBJECTTYPE = 1 AND Table1.OBJECTTYPE = 1 AND Table1.CHILDOBJECTTYPE = 2 order by SECURITYROLE.Name asc;

 

Keep daxing!!


Monday, September 20, 2021

CUSTOMER CHANGE APPROVALS IN DYNAMICS 365 FINANCE AND OPERATIONS.

CUSTOMER CHANGE APPROVALS IN DYNAMICS 365 FINANCE AND OPERATIONS

In certain scenarios, few organizations may need approval process for changing the existing customer master data such as Name, Bank account etc. D365 F&O has brought a new workflow approval feature named as “Proposed customer change workflow” to meet this requirement.

By inculcating this feature, the user can configure the approval mechanism to have a hands on control on the updates to the specified business critical customer master data fields. This feature enables the change request to be approved before the changes get committed to the customer master record. 

PARAMETERS SETUP 

Below are the parameters that are required to enable this feature. Mark the Enable customer approvals check box under Accounts receivable > Setup > Accounts receivable parameters > General (Tab) > Customer approval (Tab), as shown below.

Allocate the Data entity behaviour value under Accounts receivable > Setup > Account receivable parameters > General (Tab) > Customer approval (Tab), from one of the 3 available lookup options, as appropriate, to control the data import behaviour through data entities.

·         Allow changes without approval - Customer record can be updated without approval.

  • Reject changes – Changes cannot be made to customer record.
  • Create change proposals – Changes to the fields will be treated as proposed changes and subject to required approvals. 
 

Enable the check box against each field that needs approval, under Accounts receivable > Setup > Account receivable parameters > General (Tab) > Customer approval (Tab), as shown below. In this example, Test field is enabled to illustrate the process.    

 

WORKFLOW CONFIGURATION

Configure a new workflow by selecting the workflow type named Proposed customer change workflow under Accounts receivable > Setup > Accounts receivable workflows, as shown below and setup the workflow as per business need.

UPDATE CUSTOMER DATA

Once the workflow is configured, try to update the Test for the existing customer from Accounts receivable > Customers > All customers > Edit.

Change the Test and observe that system will pop up a dialog by showing the current and proposed Test, for your review. And one can discard the changes if required.


 
Close the Proposed change dialog and submit the change to workflow.

 

Approver can click on the proposed change button on the customer master record, to view the proposed changes in the customer data before taking an appropriate action.

 

If the workflow is approved by the approver, then the changed data will get updated in Test field.

                                            

 

 

Once the workflow approval request is completed then the system will update the Test in the customer master with the proposed field value.

 

Add new field for Proposed customer changes workflow 

  • Step1. Create extension for CustTableChangeProposalField and an Enum.  add an element with name Test. 

  • Step2. Create post event handler or COC for CustTableChangeProposalFieldEnablement/InitializeAll method and add this line for your field

 

[ExtensionOf(tableStr(CustTableChangeProposalFieldEnablement))]

final class CustTableChangeProposalFieldEnablement _Extension

{

    /// <summary>

    /// Creates entries for all fields if they do not already exist.

    /// </summary>

    public static void initializeAll()

    {

        next initializeAll();

        CustTableChangeProposalFieldEnablement::findOrCreate(CustTableChangeProposalField::Test);

    }

}

  • Step 3. Create extension of CustTableChangeProposal table and add Test field and an enum filed IsChangedTest.
  

  • Step 4. Create cust change proposal form extension and add a new group for Test. This will enable to see your changes to Test filed in the proposal changes form from Customer form when workflow is activated


 
Step 5 . Create extension for CustChangePraposal form write the below code in disableDiscardbutton() method and ShowHideGroups() method

[ExtensionOf(formStr(custChangeProposal))]

final class CustTableChange_Extension

{

    /// <summary>

    /// Controls the visibility of groups representing the individual grid rows

    /// </summary>

     public void showHideGroups()

    {

        next showHideGroups();

        TestGroup.visible(CustTableChangeProposal.IsChangedTest);

    }

    /// <summary>

    /// Disable all the DiscardTest button on the form

    /// </summary>

    protected void disableDiscardButtons()

    {

        next disableDiscardButtons();

        DiscardTest.enabled(false);

    }

}

  • Step 6. Write the below code in Onclicked DiscardTestChange button of form CustChangeProposal

/// <summary>

    /// used to create new field and update the tabel CustTableChangeProposal

    /// </summary>

    /// <param name="sender">DiscardTest</param>

    /// <param name="e">Clicked</param>

    [FormControlEventHandler(formControlStr(CustChangeProposal, DiscardTest), FormControlEventType::Clicked)]

    public static void DiscardTest_OnClicked(FormControl sender, FormControlEventArgs e)

    {

        CustTableChangeProposal CustTableChangeProposal = sender.formRun().dataSource(1).cursor();

        ttsbegin;

        CustTableChangeProposal localRecord = CustTableChangeProposal::findByCustRecId(CustTableChangeProposal.CustTable, true);

        localRecord.IsChangedTest= NoYes::No;

        localRecord.update();

        ttscommit;

    } 

  • Step 7 : Create extension for table CustTableChangeProposal and extend methods like isRedundant() and setFlagForChangedField()

 

[ExtensionOf(tableStr(CustTableChangeProposal))]

final class CustTableChangeProposal_Extension

{

    /// <summary>

    /// Sets the flag marking a change for a specific field.

    /// </summary>

    /// <param name = "_controlledField">CustTableChangeProposalField</param>

   public void setFlagForChangedField(CustTableChangeProposalField _controlledField)

    {

        next setFlagForChangedField(_controlledField);

        switch (_controlledField)

        {

            case CustTableChangeProposalField::Test :

                this.IsChangedTest = NoYes::Yes;

                break;

        }

    }

 

/// <summary>

/// Checks if the record contains no active changes, and is therefore redundant.

/// </summary>

/// <returns>True if the record contains no changed field information;false    otherwise.</returns>

    public boolean isRedundant()

    {

        boolean ret = next isRedundant();

        boolean Ischanged;

        if (ret)

        {

            Ischanged = !(ret || this.IsChangedTest);

                if(! Ischanged)//Do not delete the change

            {

                ret = false;

            }

        }

        return ret;

    }

}

 

and create event handler to update IsChangedTest field  

   

/// <summary>

/// Adjusts values to keep track of changes and executes the update

/// </summary>

/// <param name="args">CustTableChangeProposal</param>

    [PostHandlerFor(tableStr(CustTableChangeProposal),tableMethodStr(CustTableChangeProposal, update))]

    public static void CustTableChangeProposal_Post_update(XppPrePostArgs args)

    {

        CustTableChangeProposal changeProposal = args.getThis();

        if (changeProposal.Test != changeProposal.orig().Test)

        {

            changeProposal.IsChangedTest = NoYes::Yes;

        }

    } 

} 

  • Step 8: Create extension for CustTable form and place the below code. Modified event on the Test would be captured and created as a change proposal for workflow

     /// <summary>

    /// This method is used for modify the newly added test control.

    /// </summary>

    /// <param name="sender">CustTable_Test</param>

    /// <param name="e">Modified</param>

    [FormControlEventHandler(formControlStr(CustTable, CustTable_Test), FormControlEventType::Modified),SuppressBPWarning('BPParameterNotUsed', "Parameter e is required")]

    public static void CustTable_Test_OnModified(FormControl sender, FormControlEventArgs e)

    {

        FormRun  formRunCustTable = sender.formRun() as FormRun;

        FormDataSource CustTableFD=sender.dataSourceObject();

        CustTable    custTableRecord=CustTableFD.cursor();

       

        formRunCustTable.modifiedControlledField(

                    fieldNum(CustTable, Test),

                    fieldNum(CustTableChangeProposal, Test),

                    custTableRecord,

            CustTableChangeProposalField::Test);

    } 

  • Step 9: The last step would to update the currency filed in the Customer table after the workflow, So create extension for CustTableChangePraposalApply and write the below code

 

[ExtensionOf(classStr(CustTableChangeProposalApply))]

final class CusttableChangeProposalApply_Extension

{

    /// <summary>

    /// Sets values of <c>CustTable</c> fields based on change proposal data.

    /// </summary>

    /// <param name = "_custTableToUpdate">CustTable</param>

    /// <param name = "_dirPartyToUpdate">DirPartyTable</param>

    protected void initializeCustTable(CustTable _custTableToUpdate, DirPartyTable _dirPartyToUpdate)

    {

        if(proposal.IsChangedTest)

        {

            _custTableToUpdate.Test = proposal.Test;

        }

        next initializeCustTable(_custTableToUpdate,_dirPartyToUpdate);

    } 

}

Keep Daxing !!