Tuesday, December 27, 2022

How to set count on Tile using X++ (Update tile count runtime)

Deal All,

Today we are going to learn about how to set the count value on Tiles using x++ query. I came across this scenario during my resent customization. This will be helpful when you have requirement to filter tiles data count on the basis of unbound control of the form and that control value is not belongs to any of your dataSource columns.

Requirement: Add Integer control on the form and upon modification of that control update the count of Tile with the condition of records created before given number of days.

Logic: ((todays date  - Created Date) > number of days given in the control) then show on the count otherwise not.

Implementation Steps :

  1. Create AOT query to show all the record count without number of days filter.
  2. Create Tile and set below 2 properties. 
    Query: query name
    Type: count.
  3. Create new form.
  4. Add new Integer filter control on the form and set auto declaration property to Yes. (No of Days)
  5. Add new Tile button on your form and set tile property with above created tile name.
  6. Override the getData() and clicked method of your Tile button and add below code.
public void clicked()
{
    #Task
    super();
    element.task(#taskRefresh);
}

public TileButtonControlData getData()
{
    TileButtonControlData ret;
    ret = super();

    if(FilterNoOfDays.value() != 0)
    {
        int recordCOunt = element.countFromQuery(queryStr(TestTilePOLInes));                                               ret.strTileData(any2Str(recordCOunt));     
        return ret;
    }
}

7. add new method on form level with below code to get the count from query with No of days condition.

public Integer countFromQuery(str _query)
{
    int totalRecords;
    Query query = new Query(_query);
    QueryRun qr = new QueryRun(query);

    while (qr.next())
    {
        TESTAllPOLinesView dsTest = qr.get(tablenum(TESTAllPOLinesView));
        int dateDiff = today() - DateTimeUtil::date(dsTest.CreatedDateTime1);
        int filterValue = FilterNoOfDays.value();
        if( dateDiff > filterValue)
        {
            totalRecords++;
        }
    }
    return totalRecords;
}

8.Build and synch your project area and check the result by modifying the Number of days filter control.
 

Saturday, December 24, 2022

How to add range on AOT query and X++ with two different columns.

Hi All,
Let's learn about how to add two different data source columns range on one column range in AOT Query. also i am covering how can we apply same on X++ query.


Apply range on AOT Query:


Only the point to be consider is we need to use parenthesis correctly and Proper enum name - 
DocumentStatus::None.

Apply range on X++ Query.

Override the execute query method of your form Datasource and add below code.

public void executeQuery()
{

//Clear ranges.
this.query.dataSourceTable(tableNum(yourDatasourcename)).clearRanges();

Query query = new Query(this.query());


QueryBuildDataSource TestAllSOLinesView_ds1 = query.dataSourceTable(tableNum(TestAllSOLinesView));

queryBuildRange queryBuildRange = TestAllSOLinesView_ds1.addRange(fieldNum(TestAllSOLinesView, DocumentStatus));

queryBuildRange.value(strFmt('((DocumentStatus == %1) || ((TestConfirmationStatus == "%2") 
&& (DocumentStatus != %1)))',any2int(DocumentStatus::None),
any2int(TestConfirmation::ToBeConfirmed)));

this.query(query);

super();

}

AOT Range on 2 different date columns
 refer below screen shot - I have set the value property with greater than condition on two date column of my data source.

ex - (TestReqShippingDate > TestAllPOLinesView.TestConfirmedShippingDate)



How to create multi selection lookup on form control

Hi All,
In this article will see how to create multi selection lookup on a form control.

For this we need to create one AOT query like CustTablelookup. for that you can refer the documents provides by Microsoft docs.

Expected Result is below: 








Step 1: Create a control on form and set auto declaration property to yes. 







Step 2: Override the Init() method of form and add below code.

public class TestLookupTestControl extends FormRun
{
        SysLookupMultiSelectCtrl        custAccountMultiSelectControl;
}

public void init()
{

        super();

        custAccountMultiSelectControl = SysLookupMultiSelectCtrl::construct(element,FilterCustAccount, queryStr(CustTablelookup));       

}

Thats It. Happy Coding.



Monday, December 12, 2022

D365 F&O Warehouse management application customization Part 2- Perform auto click from x++ code.

Hi All,

Welcome to the second part of this series. In this blog will see how we can perform the auto click after auto populating values.

This is required because in standard logic system is working like on first click it will fetch item id , then on second click user will enter the quantity and so on. So if we are auto populating all the values in first click then we need to skip other clicks and process for the next form directly. Refer the issue on this link.

As we have learn in the first blog, you need to identify the child class according to your requirement and execution mode define in your menu item setup.
Below class is the extension of WHSWorkExecuteDisplayPOReceiving and created COC for displayForm() method.

Inside displayForm() method we need to identify the logic to trigger the auto button click.
In below case I have written a logic like once all the values are not equals to blank then perform auto click and for safer side to avoid recursion I have added one flag in pass object.

[ExtensionOf(classStr(WHSWorkExecuteDisplayPOReceiving))]
final class WHSWorkExecuteDisplayPOReceiving_ModelTest_Extension
{
    // COC of display form method in extension class.
    public container displayForm(container _con, str _buttonClicked)
    {
        Container returnedCon;
        #WHSWorkExecuteControlElements
        #WHSRF

        //Next statement

        returnedCon = next displayForm(_con, _buttonClicked);

        //Logic to skip the extra clicks goes here.
        if(step == 1 && !pass.exists("AutoClickOk")&&
        mode == WHSWorkExecuteMode::PurchaseOrderItemReceivingAndLocate)
        {
                pass.insert("AutoClickOk",'1');
                
                // this line will perform auto click
                returnedCon = this.displayForm(returnedCon, #RFOk); 
        }
        
        return returnedCon; 
    }
}


That's It. Lets enjoy the success of auto click and stay tuned for the next blog.

D365 F&O Warehouse management application customization Part 1- Auto populate the value to a standard field.

Hi All,
I hope everyone is doing great and learning new things. 
Here I am coming with a new blog to understand and guide everyone to learn the customization in Warehouse Management application. As you can see in the screenshot below, We have received by purchase order form on this form we will scan the QR string and auto populate the remaining field values.

This is the example of QR string format:  "PoNum,ItemId,Quantity,date"



As I understand from the code WHSWorkExecuteDisplay.displayForm() is the important method to create control and assign the values. It is an abstract method of class WHSWorkExecuteDisplay so that according to our requirement we need to figure out under which process you need to implement your changes to and then find its child class.

In my example child class WHSWorkExecuteDisplayPOReceiving so I have created an extension class for it and added COC for displayForm() method.

[ExtensionOf(classStr(WHSWorkExecuteDisplayPOReceiving))]
final class WHSWorkExecuteDisplayPOReceiving_ModelTest_Extension
{
    
}

All the controls on the form and its values are assigned through the container of display form method parameter(_con). so, to assign our values we need modify the same container.

below logic will take scanned value of QR code from PONum field then convert it to the container.

// COC of display form method in extension class.
 public container displayForm(container _con, str _buttonClicked)
 {
    if( mode == WHSWorkExecuteMode::PurchaseOrderItemReceivingAndLocate &&
         step == 1)
    {
            container      returnedCon, qrValueContainer;
            PurchId         purchId;
            ItemId           itemId;
            str                 quantityStr;
            const str       fullQRValueConstText        = "FullQRValue";
            #WHSWorkExecuteControlElements
            #WHSRF

            str  fullQRValue = this.getControlDataFromContainer(_con,#PONum);
        
            qrValueContainer = str2con(fullQRValue,'@');

            if(conLen(qrValueContainer) > 1)
            {
                pass.insert(fullQRValueConstText, fullQRValue);

                purchId       =  conPeek(qrValueContainer,1);
                quantityStr  =  conPeek(qrValueContainer,2);
                itemId         =  conPeek(qrValueContainer,3);

                _con = this.setControlDataFromContainer(_con, #PONum, purchId);
                stepLocal = step;
            }

        returnedCon = next displayForm(_con, _buttonClicked);
    
           if( mode == WHSWorkExecuteMode::PurchaseOrderItemReceivingAndLocate)
            {
                    // you can add logic here when to replace.
                    if(stepLocal == 1 && pass.lookup(#PONum) != '')
                    {
                        returnedCon  this.setControlDataFromContainer(returnedCon,                                                                                         #Qty,  strRem(quantityStr,'Q'));
                        returnedCon = this.setControlDataFromContainer(returnedCon, #ItemId, itemId);                        
                    }
            }
    }
    return returnedCon;
 }    

That's It. Happy Coding.
Please comment if you have faced any challenge to implement this.

Post partial packing slip in D365FO

How to Post a Partial Packing Slip in D365FO and AX 2012 How to Post a Partial Packing Slip in D365FO and AX 2012 Understanding t...