Thursday, December 30, 2021

selectForUpdate with fieldId in D365Fo using x++

selectForUpdate with fieldId in D365Fo using x++ . Just check below method.


static void update(Args _args) { CustTable custTable; TestCustomer testCustomer; void updateByField(FieldId _testCustomerFieldId, FieldId _custTableFieldId) { if (custTable.(_custTableFieldId)) { testCustomer.(_testCustomerFieldId) = custTable.(_custTableFieldId); } } void updateTable(Common _tableBuffer) { if (_tableBuffer.validateWrite()) { _tableBuffer.update(); } } while select testCustomer { custTable = CustTable::find(testCustomer.CustAccount); if (custTable) { ttsBegin; testCustomer.selectForUpdate(true); updateByField(fieldNum(testCustomer, CustGroupId), fieldNum(custTable, CustGroup)); updateByField(fieldNum(testCustomer, Currency), fieldNum(custTable, Currency)); updateByField(fieldNum(testCustomer, Name), fieldNum(custTable, InventSiteId)); updateByField(fieldNum(testCustomer, NoYesId),                                                                            fieldNum(custTable, InterCompanyDirectDelivery));

updateTable(testCustomer); ttsCommit; } } }

Before:

After run the method:

Output


Keep Daxing!!

Tuesday, December 28, 2021

Passing Temp table values from one form to other form in D365fo using X++

Hi guys, today post is for passing Temp table values from one form to other form using List in D365fo.

I got requirement like I need to pass the selected temp table values from one form to other form and I need to do some actions based on temp table values. 

For this we can use 

  • List
  • Set
  • Container
Examples: Use any one from this.
-----------------------------------------------------------------------------------------------------------------------------
List: 

//Parent Class Button Clicked method.

void clicked() {

    List myList; TempTable tmpLoc; ; myList = new List(Types::Record);     if (TempTable_ds.Anymarked())// check user selected the record or not. for (tmpLoc = getFirstSelection(TempTable_ds); tmpLoc; tmpLoc = TempTable_ds.getNext()) { myList.addStart(tmpLoc); }

//Calling child form: Any one we can use.

Way1: Args args; FormRun formRun; args = new Args(); args.parmobject(myList); args.name(formstr(Myform)); formrun = classfactory.formrunclass(args); formrun.init(); formrun.run(); formrun.wait();

Way 2:

    Args args;

    args.parmObject(myList);

    new MenuFunction(menuitemdisplaystr(menu item name), MenuItemType::Display).run(args);

}

 //Child class init method;

public void init() {

    List myList; ; if (element.args().parmObject()) { myList = element.args().parmObject(); } //Iterator ListIterator listterator = new ListIterator(myList); while (literator.more()) { tmpTable.data(literator.value()); } //Enumerator ListEnumerator enumerator = myList.getEnumerator(); while(enumerator.moveNext()) { tmpTable.data(enumerator.current()); }

}

-----------------------------------------------------------------------------------------------------------------------------

Set:

//Parent Class Button Clicked method.

void clicked() {

    Set records; TempTable tmpLoc; ; records = new Set(Types::Record); for (tmpLoc = getFirstSelection(TempTable_ds); tmpLoc; tmpLoc = TempTable_ds.getNext()) { records.add(tmpLoc); }

//Calling child form: Any one we can use.

Way1:

Args args; FormRun formRun; args = new Args(); args.parmobject(records); args.name(formstr(Myform)); formrun = classfactory.formrunclass(args); formrun.init(); formrun.run(); formrun.wait();

Way 2:

    Args args;

    args.parmObject(myList);

    new MenuFunction(menuitemdisplaystr(menu item name), MenuItemType::Display).run(args);

}

//Child class init method; 

public void init() {

    Set records; ; if (element.args().parmObject()) { records = element.args().parmObject(); } //Iterator SetIterator recordsIterator = new SetIterator(records);//element.args().parmObject() while (recordsIterator.more()) { tmpTable.data(recordsIterator.value()); //tmpTable.linkPhysicalTableInstance(recordsIterator.value()); recordsiterator.next(); } //Enumerator SetEnumerator enumerator= records.getEnumerator(); while (enumerator.moveNext()) { tmpTable.data(enumerator.current()); }

}

-----------------------------------------------------------------------------------------------------------------------------

Container:

//Parent Class Button Clicked method. 

void clicked() {

    container                   packed;
    Set                         records;
    TempTable                   tmpLoc;
    ContainerClass              containerClass;// For container we need to use this.
    ;
    
    records = new Set(Types::Record);
    for (tmpLoc = getFirstSelection(TempTable_ds); tmpLoc; tmpLoc = TempTable_ds.getNext())
    {
        records.add(tmpLoc);
    }

    packed          = records.pack();
    containerClass  = new ContainerClass(packed);
    

//Calling child form: Any one we can use.

Way1:

    Args           args;
    FormRun        formRun;

    args = new Args();
    args.parmobject(containerclass);
    args.name(formstr(Myform));

    formrun = classfactory.formrunclass(args);

    formrun.init();
    formrun.run();
    formrun.wait();

Way 2:

    Args args;

    args.parmObject(myList);

    new MenuFunction(menuitemdisplaystr(menu item name), MenuItemType::Display).run(args);

}

//Child class init method:

public void init() {
    ContainerClass containerClass; ; if (element.args().parmObject()) { containerClass = element.args().parmObject(); } SetIterator recordsIterator; container packed = containerClass.value(); ; recordsIterator = new SetIterator(Set::create(packed)); while (recordsIterator.more()) { tmpTable.data(recordsIterator.value()); //tmpTable.linkPhysicalTableInstance(recordsIterator.value()); recordsiterator.next(); }
}
--------------------------------------------------------------------------------------------

Keep Daxing!!

Container function in D365fo

Hi guys, today our topic is Container function in D365fo      

Container: It will stores the multiple values with multiple data types.


    container  myContainer= ['Hi',1,2,'Hello'];

    anytype    value;
 
    ConIns:
        Insert the values into container.
    
        myContainer = conIns(myContainer,1,'test1');
    
    ConPeek:
        Get the value from container.

        value  = conPeek(myContainer,1);//your container name, position.

    ConPoke:
        Update the value in container.

        myContainer = conpoke(myContainer,1,'test2');
    
    Condel:
        Delete the values from Container.
    
        secondContainer =conDel(secondContainer,2,1);

    ConNull:    
        clear all the value from container.
    
        myContainer = conNull() ;

    ConLen:
        Find the length of the container.

        int lenght= conLen(myContainer);

    Confind:
        This function is return the Position of searched value. 
            if value is not found it will return 0.

        int position = conFind(secondContainer,'Hello');

 
    Con2Str:
        This function is used to convert container to string. 

        str     string= con2Str(secondContainer);

    Con2List:

        This function converts the container into list.

        List myList = con2List(secondContainer);
    
    Con2Buf: converts container into record. con2Buf(myContainer, mytable); ConView: It will show the container values. conView(myContainer); str2Con: It converts string into container. str2Con(string); str2Con(string, '/');// It will separate the values upon '/'.

    Convert Set into container:
    
        Set         records = new Set(Types::Int64);
        container   packed  = records.pack();
    
    Convert Set into container:
    
        SetIterator     recordsIterator = new SetIterator(Set::create(container));
                                            
 

     Loop the container:

    for (int i = 1; counter <=conLen(secondContainer); i++)
    {
        info(conPeek(secondContainer, i));
    }


 Keep Daxing!!

Filter records in form in D365fo

Hi guys, Today we see how to filter the records in form using X++.

  • If it's a new form directly write the below code.
  •  If it's a standard form. create extension class.
Here we have 2 ways. Follow anyone.

Way 1:

    public QueryBuildRange qbr;//declare this variable globally. public void init()// dataSource init method { super(); qbr = this.query().dataSourceTable(tableNum(InventSite)).addRange(
                                                        fieldNum(InventSite, IsActive)); } public void executeQuery()// dataSource { FormRun formRun = element; if (formRun.args().menuItemName() == menuItemDisplayStr(InventSite)) { qbr.value(queryValue(NoYes::Yes)); } next executeQuery(); 

} 


Way 2:

    public void executeQuery()// dataSource { FormRun formRun = element; if (formRun.args().menuItemName() == menuItemDisplayStr(InventSite)) { this.initializeQueryFromType(); } next executeQuery(); } public void initializeQueryFromType() { QueryBuildDataSource qbDataSource; ; qbDataSource = this.query().dataSourceTable(tableNum(InventSite)); qbDataSource.clearDynalinks(); qbDataSource.addRange(fieldNum(InventSite,                                              isActive)).value(SysQuery::value(NoYes::Yes));

}

Keep Daxing!!

Tuesday, December 21, 2021

How to add Records to include option on sys operation dialog in D365FO

 Hi guys, Today we see how to add records to include option to sys operation.




While running the batch we have to filter the data based on requirements. Instead of writing while loops. We can use query. Just follow the below steps.


Step 1: Create a static query and add data sources based on your requirement. Here I have added Vendatable.


Required fields drag to Ranges node those will be displayed in the dialog.

Sometimes we need the same data from the query. Instead of selecting the values from the front end, we can define in value property.



Step 2: Create a Contract class, add parm methods for your parameters and we have to add a few methods to get that option.

[DataContractAttribute] class TestSysOperationContract { Name name; str packedQuery; [DataMemberAttribute] public Name parmName(Name _name = name) { name = _name; return name; }

    //SysOperationControlVisibilityAttribute(false)// Hide control

[DataMemberAttribute, AifQueryTypeAttribute('_packedQuery', querystr(TestVendorQuery)) ] public str parmQuery(str _packedQuery = packedQuery) { packedQuery = _packedQuery; return packedQuery; } public Query getQuery() { return new Query(SysOperationHelper::base64Decode(packedQuery)); } public void setQuery(Query _query) { packedQuery = SysOperationHelper::base64Encode(_query.pack()); } //public void initQuery() //{ // Query query = new Query(querystr(TestVendorQuery)); // this.setQuery(query); //} }

Step 3: Create a Controller class for calling the service class.

class TestSysOperationController extends SysOperationServiceController
{
    public static void main(Args args)
    {
        TestSysOperationController      controller;
        ;

        controller =  new TestSysOperationController();
        controller.startOperation();
    }
    public void new()
    {
        super(classStr(TestSysOperationService),
                methodStr(TestSysOperationService, process));//,
                    //  SysOperationExecutionMode::Synchronous);
        this.parmDialogCaption("Dialog Title");
    }
} 

Step 4: Create a service class to write our business logic.

class TestSysOperationService extends SysOperationServiceBase
{
    //[SysEntryPointAttribute]
    public void process(TestSysOperationContract _contract)
    {
        QueryRun    queryRun;
        VendTable   vendTable;
        ;

        // create a new queryrun object
        queryRun = new queryRun(_contract.getQuery());

        while(queryRun.next())
        {
            vendTable = queryRun.get(tableNum(VendTable));
            // Your logic.
            info(strFmt('Account - %1 , Name - %2',vendTable.AccountNum,vendTable.name()));
        }
    }

} 

Ends.............

------------------------------------------------------------------------

Sys operation :

If we need to run this batch based on the caller record.


We need to change the logic in the Controller class.

class TestSysOperationController extends SysOperationServiceController { public static void main(Args args) { TestSysOperationController controller; ; controller = TestSysOperationController::newFromArgs(args); controller.startOperation(); } public static TestSysOperationController newFromArgs(Args _args) { TestSysOperationController testController; TestSysOperationContract contract; testController = new TestSysOperationController(); //controller.initializeFromArgs(_args); //contract.initQuery(); if(_args && _args.dataset() == tableNum(VendTable)) { VendTable vendTable; Query query;

            //controller.getDataContractObject()//// for sys operation             //controller.parmReportContract().parmRdpContract() // For Report
contract = testController.getDataContractObject('_contract');
                      // '_contract' this name is from service class method parameter buffer. vendTable = _args.record(); if (vendTable) { query = new query(queryStr(TestVendorQuery));                 //query = contract.getQuery();
//query.clearQueryFilters(); query.dataSourceTable(tableNum(VendTable)).clearRanges(); query.dataSourceTable(tableNum(VendTable)).addRange(fieldNum(VendTable, VendGroup)).value(queryValue(vendTable.VendGroup)); query.dataSourceTable(tableNum(VendTable)).addRange(fieldNum(VendTable, AccountNum)).value(queryValue(vendTable.AccountNum)); contract.setQuery(query); } } return testController; } public void new() { super(classStr(TestSysOperationService), methodStr(TestSysOperationService, process));//, // SysOperationExecutionMode::Synchronous); this.parmDialogCaption("Dialog Title"); } }

multiple records
protected void initContract(Args _args)
{
    MyContract   contract;
    Query        q;
    ;
    contract = this.getDataContractObject('_contract'); 
    q = contract.getQuery();
    
    MultiSelectionHelper multiSelectionHelper;

    multiSelectionHelper = MultiSelectionHelper::createFromCaller(_args.caller());
    multiSelectionHelper.createQueryRanges(q.dataSourceTable(tableNum(MyTable)), 
                                                        fieldStr(MyTable, JournalId));
    
    qbr = findOrCreateRange_W(q.dataSourceTable(tableNum(MyTable)), 
                                                        fieldNum(MyTable, JournalId));

    contract.setQuery(q);
}





Keep daxing!!





Tuesday, December 7, 2021

How to get Default Dimension value for the Record in D365FO

 How to get Default Dimension value for the Record in D365FO using x++.


Way 1: by class

public DimensionValue getDimensonValue(LedgerDimensionValueSet     _defaultDimension)
{
    DimensionAttributeValueSetStorage   dimensionAttributeValueSetStorage;
    DimensionAttribute                  dimensionAttribute;
    DimensionValue                      dimensionValue;
    ;

    #define.DimensionName("CostCenter")// 'DimensionName'

    dimensionAttributeValueSetStorage = dimensionAttributeValueSetStorage::find(_defaultDimension);

    dimensionAttribute  = dimensionAttribute::findbyname(#DimensionName);
    dimensionValue      = dimensionAttributeValueSetStorage.getDisplayValueByDimensionAttribute(
                                                                    dimensionAttribute.recId);
    return dimensionValue;
}

Way 2: by View

Public DimensionValue getDimensonValue(LedgerDimensionValueSet _defaultDimension) { DefaultDimensionView defaultDimensionView; ; select firstonly DisplayValue from defaultDimensionView where defaultDimensionView.Name == 'dimensionName' && defaultDimensionView.DefaultDimension == _defaultDimension; return defaultDimensionView.DisplayValue; }



Keep daxing!!



How to remove the value of a default dimension of a record in D365FO

 How to remove the value of a default dimension of a record in D365FO.


public void removeDimension(LedgerDimensionValueSet _defaultDimension) { DimensionAttributeValue dimAttrValue; DimensionAttribute dimAttr; DimensionAttributeValueSetStorage dimensionAttributeValueSetStorage; dimensionAttributeValueSetStorage = DimensionAttributeValueSetStorage::find(_defaultDimension); dimAttr = DimensionAttribute::findByName('DimensionName'); dimensionAttributeValueSetStorage.removeDimensionAttributeValue( DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttr, 'DimensionValue').RecId); } 


Keep daxing!!

How to change the value of a default dimension of a record in D365FO

Today, we see how to change the value of a default dimension of a record in D365FO using X++.


public LedgerDimensionValueSet updateDimension(LedgerDimensionValueSet _defaultDimension) { DimensionAttributeValue dimAttrValue; DimensionAttribute dimAttr; DimensionAttributeValueSetStorage dimensionAttributeValueSetStorage; LedgerDimensionValueSet defaultDimension; dimensionAttributeValueSetStorage = DimensionAttributeValueSetStorage::find(_defaultDimension); dimAttr = DimensionAttribute::findByName('DimensionName'); dimAttrValue = DimensionAttributeValue::findByDimensionAttributeAndValue(dimAttr,                         'DimensionValue', false, true);

if(dimAttrValue) { dimensionAttributeValueSetStorage.addItem(dimAttrValue); defaultDimension = dimensionAttributeValueSetStorage.save(); } return defaultDimension; } 


Keep daxing!!

Monday, December 6, 2021

Get label for table using x++ in D365FO

 Hi, guys today we see how to get a table, fields label value using x++.


Info(strfmt('Table name : %1, Lable : %2 ', tablestr(VendTable), tablePName(VendTable)));



tablestr --> It will retun table name. O/P -> VendTable.

tablePName--> It will retun lable name of table. O/P -> Vendors.


Field label:

info(fieldPName(VendTable, AccountNum));


Label, Name, and Data type of all fields of any table:

DictTable dt=new SysDictTable(tableNum(CustTable)); FieldId _fieldId= dt.fieldNext(0); DictField _dictField; while(_fieldId) { _dictField =dt.fieldObject(_fieldId); info(strFmt("Field Name %1 , Field Lable %2 and Field Type %3",
                    _dictField.name(),_dictField.label(),_dictField.type())); _fieldId= dt.fieldNext(_fieldId); }


Keep Daxing!!

Monday, November 29, 2021

Create a New custom service in D365FO

 Hi guys, Today we see how to create a custom service in D365FO using X++.


In custom service, we have Inbound and Outbound services.

Inbound service: Get the data from 3rd party application and do some operations in D365Fo.

Outbound service: Send the data from D365Fo to 3rd party application.

components required:

  • Service class
  • Business logic class (Instead of writing the logic in the service class I created a new class)
  • Contract class
  • Service object
  • Service group object
Link : Url/api/services/serviceGpName/serviceName/OpertaionName.

  • OpertaionName(method name) is exposed to the outside systems.
  • HTTP web request. (Java client/Postman/dot net-based application)
  • We can call this API from any App.
  • 3rd party application will send data to D365FO and D365FO will store the data and send a response "Success" or "failed" based on business operation.
  • I took a simple example. I send the customer data to D365FO If the customer exists it will update the customer name otherwise it will insert the data in D365FO. I have used a custom table.


1. Create a contract class and parm methods.

[DataContractAttribute]
class TestCustomServiceDataContract
{
    str customer, name;

    public TestCustomServiceDataContract construct()
    {
        return new TestCustomServiceDataContract();
    }

    [DataMemberAttribute('Customer account')]
    public str parmCustomer(str _customer = customer)
    {
        customer = _customer;

        return customer;
    }

    [DataMemberAttribute('Customer name')]
    public str parmName(str _name = name)
    {
        name = _name;

        return name;
    }

}

2. Create service class and method is in public.

class TestCustomServiceDataService
{
    public str customers(TestCustomServiceDataContract     _contract)
    {
        return TestCustomServiceBussinessLogic::getCustomer(_contract);
    }
} 

3. Bussiness logic class.

class TestCustomServiceBussinessLogic
{
    public static str getCustomer(TestCustomServiceDataContract     _contract)
    {        
        TestCustomers       customer = TestCustomers::find(_contract.parmCustomer(), true);

        if (customer)
        {
            ttsbegin;
            customer.Name = _contract.parmName();
            customer.update();
            ttscommit;

            return 'Success';
        }
        else
        {
            customer.clear();
            customer.Customer   = _contract.parmCustomer();
            customer.Name       = _contract.parmCustomer() + ' ' + _contract.parmName();
            customer.insert();

            return 'Success';
        }

        return 'Failed';
    }

}

4. Create Service.
        




5. Create a Service Group.



Link : Url/api/services/serviceGpName/serviceName/OpertaionName

Url/api/services/TestCustomServiceGroup/TestCustomService/customers

Use the above link in postman.


Remove custom service default parameter: id in D365FO:


Write the below line on top of the contract to remove that "Id".
[DataContractAttribute, Newtonsoft.Json.JsonObjectAttribute(IsReference = false)]

Multiple records:

{ "record": [ { "ID": "140127-000003", "EffectiveDate": "2022-06-05", "IsTrue": "Yes", "DueDate": "2022-06-05T13:49:51.141Z" } ] }

We need to build a method like the below in the service class:

[AifCollectionType('record', Types::Class, classStr(TestDataContract))] [AifCollectionType('return', Types::Class, classStr(Test2DataContract))] public List updateStockOnHand(List record) { }

For the above example code is written in the below link. Please check.



Keep daxing!!


Generate QR code using x++ in SSRS report

 Hi guys, Today we see how to Generate QR codes using x++ in D365FO SSRS reports. We can generate QR codes in two ways. Please check below.


Steps :

            1. Need to create container filed in Temp table.


            2. Add Way1/Way2 code in DP class and calling that method while inserting data into temp table. Like below.

                    headerTmp.Image = this.QRCode('TEST');// Your method.

                     headerTmp.insert();

            3.click restore on report

            4. Add image field in design                          


            5. Image Properties :

      • Select the image source : Database
      • Use this field : Field from Table
      • Use this MIME type : image/bmp               



Way 1:

using QRCoder;
public class GetQRCode
{
public static container QRCode(JournalTable  _jour)
{
    Microsoft.Dynamics.ApplicationSuite.QRCode.Encoder   qrCode;
    str                                 QrCodeBase64String;
    System.String                       netString;
    str                                 tempFileName;
    System.Drawing.Bitmap               netBitmap;
    Bitmap                              imageQR;
    FileIOPermission                    perm;
    BinData                             binData;
    container                           imageContainer;
    Str1260                             qrString;
    real                                taxWithoutVat;
    QRCodeGenerator.ECCLevel            eccLevel;
    QRCodeGenerator                     qrGenerator = new QRCodeGenerator();
    ;

    qrCode          = new Microsoft.Dynamics.ApplicationSuite.QRCode.Encoder();
    //qrString        = strFmt("https://www.google.com/");
    qrString        = strFmt("Supplier name: %1", CompanyInfo::findDataArea(_jour.DataAreaId).Name);
    qrString        += strFmt("\nInvoice number: %1", _jour.InvoiceId);
    qrString        += strFmt("\nInvoice Date: %1", _jour.InvoiceDate);
    qrString        += strFmt("\nTotal amount with VAT: %1", _jour.InvoiceAmount);

    netBitmap       = qrCode.Encode(qrString);

    binData         = new binData();

    QrCodeBase64String  = qrString;
    tempFileName        = qrCode.GetTempFile(QrCodeBase64String);

    perm  = new FileIOPermission(tempFileName,'RW');

    perm.assert();
    binData.loadFile(tempFileName);
    imageContainer          = binData.getData();

    // header.QRValue = imageContainer;
    return imageContainer;
}
}

==============================================================================

Way 2:

using QRCoder;
public class GetQRCode
{
    public static container QRCode(SalesId _salesId)
    {
        Microsoft.Dynamics.ApplicationSuite.QRCode.Encoder  
            qrCode = new Microsoft.Dynamics.ApplicationSuite.QRCode.Encoder();
        System.Drawing.Bitmap       bitmap;
        container                   imageContainer;
        str                         url= strFmt("%1'%2'", Parameters::find().QRCodeUrl, _salesId);
        ;        

        System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();

        bitmap = qrCode.Encode(url);

        bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat::get_Png());
        //bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat::Png);

        imageContainer = Binary::constructFromMemoryStream(memoryStream).getContainer();

        return imageContainer;
    }
}
-------------------oR------------------------------------
    private container QRCode(str _value) { Microsoft.Dynamics.ApplicationSuite.QRCode.Encoder qrCode = new Microsoft.Dynamics.ApplicationSuite.QRCode.Encoder(); System.IO.MemoryStream memoryStream = new System.IO.MemoryStream(); System.Drawing.Bitmap bitmap; bitmap = qrCode.Encode(_value); bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat::Png); return Binary::constructFromMemoryStream(memoryStream).getContainer();; }


Keep daxing!!