Pages

Tuesday, December 30, 2014

Error while confirming/creating Purchase Order - WHSAutoCreateLoadLine incorrectly called.



Solution: 
To overcome the above issue, follow the below steps.
1. Reset usage data.
2. Remove log files from user.
3. Refresh the cache data. AOT-->Tools-->Cache -> Refresh all nodes.
It is working fine.

Monday, February 17, 2014

Exchange Rate field Enable in AX 2012

HI All

In standard AX, the AP invoice journal and the general journal contain the field for currency exchange rate. However, this field by default is not editable.

Path: Accounts payable à Journals à Payment journal à Lines à General tab
 
by default in standard this field is non editable .

Solution : To make this field as editable 
AOT-->Classes-->LedgerJournalFormTrans-->setExchRateEnabled() Method. Just comment this whole code automatically Exchange rate and Secondary exchange rate fields should get enabled.



Monday, February 3, 2014

AX SSRS Error: The request failed with HTTP status 401: Unauthorized.


In AX, when certain users attempt to access an SSRS report in an environment, they are getting the error 'The request failed with HTTP status 401: Unauthorized' (Figure 1 below). This was occurring for all reports for this user. Other users were able to access the report perfectly fine. The user was able to run everything perfectly the day before. The answer was Troubleshooting step 5 below: Log out of Windows instance and log back in. I'll provide the long troubleshooting steps below in case someone else's issue was different.




TROUBLESHOOTING STEPS:
This issue is a permissions issue somewhere. At this point, we need to determine if its an issue with the user accessing the report. You can do the below troubleshooting steps. This was the order I did it in but you don't have to do it in this order. 

  1. SSRS server (server permissions)
  2. SSRS reports (SSRS permission restrictions)
  3. AX security issue (probably not but good to check)
  4. An issue with all users or just them
  5. An issue with local cache or something screwy with current windows session
Troubleshoot 1: 
To help the users identify this issue, I usually ask them to do the following on the server where they are receiving this error:

  1. Click on the Start menu in Windows
  2. Type 'cmd' in the 'Search programs and files' search line in the start menu
  3. In the command prompt, type 'ping CDBRS-MAX01'
  4. Take a screenshot of the command responses and send back the results.
    1. The results should come back with the standard ping response of 'Reply from XX.XX.X.XXX: bytes=32...''.
If #4 got a weird response or an error message, the user doesn't have access to the server. Make sure they can ping the server and have them run it again. 

Troubleshoot 2:
Having established they can access the report server, have the user access the report through the SSRS server. Have them do the following in the server where the AX client is erroring and if necessary, the SSRS report server itself:

  1. Go to internet explorer and access the SSRS report server (commonly 'http://[SSRSSERVERNAMEHERE]/reports'
  2. Once here, go to 'Dynamics AX' folder
  3. click on the report that is erroring
  4. Run the report and see if it runs. Just make sure required fields are populated.
If the report runs for them, SSRS security should be good. If it fails, make sure they're setup in the proper groups to run the reports and try again. 

Troubleshoot 3:
Have the user run the report from a server other than the one where the user was encountering the error. I logged into the AOS on their machine under my name and did the hold shift+right click on the .axc file, enter their credentials so we were running AX as that user in my server instance, and try running the report. 

Troubleshoot 4: 
Have other users attempt to run that report as well as others. Determine if its an issue with just that user. If no one is able to run the report or others, the reports may need to be deployed or the SSRS server settings need to be checked.

Troubleshoot 5:
This actually resolved the issue. Something went wrong with the user's Windows server session. I wasn't exactly sure what the issue was but having the user log out and log back in to the server resolved.

In this test, do the following:

  1. go to the person's terminal and watch them try to run the report
  2. hold shift+right click on the .axc file they were using to run the report and run as a different user. Use your own user
  3. In AX under your user in their terminal session, try to run the troubled report. 
  4. If it passes (it did in my instance), hold shift+right click on the .axc file and run as a different user, only this time use the person's credentials. For us, the user was able to run the report this way but not when just clicking on the .axc in the normal fashion
Your issue might be different but this was what it was for us so I decided to share.  Hope this helps!

How To: Clear or Delete data from an AX container



Using the conDel Function [AX 2012], a user can delete certain elements from a container. When these elements are removed, the numbering in the container will adjust accordingly so that the numbers will always be sequential

There are three parameters container conDel(container container, int start, int number):
  1. container container
    1. the container that the user wishes to have the data deleted from
  2. int start
    1. the spot in the container to start deleting values
      1. If this number is 0, it will not delete anything
      2. The number given will actually be deleted (e.g. 2 will actually include element 2 in the deletion)
  3. int number
    1. the number of elements to delete in the container
      1. If this number is larger than the container, it will delete everything from the start value on
static void daxTestDelContainer(Args _args)
{
    container   test = ['a','b','c','d','e','f','g','h','i']; 
    container   testManip = test;
    int         i; 

       
    info ("BEGIN TEST - the container data in full");
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }        

      
    info ("TEST conDel(testManip, 0, 3) - Remove 3 at spot 0");
    testManip = conDel(testManip, 0, 3);
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }    

    
    info ("TEST conDel(testManip, 1, 3) - Remove 3 at spot 1");    
    testManip = conDel(testManip, 1, 3);
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;    

    
    info ("TEST conDel(testManip, 2, 3) - Remove 3 at spot 2");
    testManip = conDel(testManip, 2, 3);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;

    
    info ("TEST conDel(testManip, 3, 5) - Remove 5 at spot 3");
    testManip = conDel(testManip, 3, 5);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

    
    // Reset the container
    testManip = test;

    
    info ("TEST conDel(testManip, 3, 50) - Remove 50 (more than container has) at spot 2");
    testManip = conDel(testManip, 3, 50);          
    // Cycle (iterate) through the container
    for (i=1; i <= conlen(testManip); i++)
    {       
       info(strFmt("%1 - %2", i, conpeek(testManip, i)));
    }

}


Count Number of Tables,Forms EDT's in AX 2012


To count number of Tables, EDT's, Form's.. etc all objects in AOT . Run the below job to get number of objects available in AOT. 



static void daxCountTablesInAX(Args _args)
{    
    // Count of all the Objects.    
    info (strFmt("Tables in AX: %1", treenode::findNode('\\Data Dictionary\\Tables').AOTchildNodeCount()));    
    info (strFmt("Extended Data Types in AX: %1", treenode::findNode('\\Data Dictionary\\Extended Data Types').AOTchildNodeCount()));    
    info (strFmt("Forms in AX: %1", treenode::findNode('\\Forms').AOTchildNodeCount()));
    info (strFmt("Parts-- Infoparts in AX: %1", treenode::findNode('\\Parts\\Info Parts').AOTchildNodeCount()));
    info (strFmt("Part- Form Parts in AX: %1", treenode::findNode('\\Parts\\Form Parts').AOTchildNodeCount()));
    info (strFmt("Part -- Cues in AX: %1", treenode::findNode('\\Parts\\Cues').AOTchildNodeCount()));
    info (strFmt("Part-- Cue Groups in AX: %1", treenode::findNode('\\Parts\\Cue Groups').AOTchildNodeCount()));
    info (strFmt("DataSets in AX: %1", treenode::findNode('\\Data Sets').AOTchildNodeCount()));
    info (strFmt("SSRS Reports in AX: %1", treenode::findNode('\\SSRS Reports\\Reports').AOTchildNodeCount()));
    info (strFmt("SSRS Reports report style templates in AX: %1", treenode::findNode('\\SSRS Reports\\Report Style Templates').AOTchildNodeCount()));
    info (strFmt("SSRS Report report datasources in AX: %1", treenode::findNode('\\SSRS Reports\\Report Datasources').AOTchildNodeCount()));
    info (strFmt("Report Images in AX: %1", treenode::findNode('\\SSRS Reports\\Report Images').AOTchildNodeCount()));
    info (strFmt("Report Templates in AX: %1", treenode::findNode('\\Reports\\Report Templates').AOTchildNodeCount()));
    info (strFmt("Report Section Templates in AX: %1", treenode::findNode('\\Reports\\Section Templates').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of Dynamics AX Model Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\Dynamics AX Model Projects').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of C Sharp Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\C Sharp Projects').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of Web Application Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\Web Application Projects').AOTchildNodeCount()));
    info (strFmt("Visual Studio Projects of Analysis Services Projects in AX: %1", treenode::findNode('\\Visual Studio Projects\\Analysis Services Projects').AOTchildNodeCount()));
    info (strFmt("Menus  in AX: %1", treenode::findNode('\\Menus').AOTchildNodeCount()));
    info (strFmt("Menu Items Display in AX: %1", treenode::findNode('\\Menu Items\\Display').AOTchildNodeCount()));
    info (strFmt("Menu Items Output in AX: %1", treenode::findNode('\\Menu Items\\Output').AOTchildNodeCount()));
    info (strFmt("MenuItems Action in AX: %1", treenode::findNode('\\Menu Items\\Action').AOTchildNodeCount()));
    info (strFmt("Reports- Report Templates in AX: %1", treenode::findNode('\\Reports\\Report Templates').AOTchildNodeCount()));
    
}

Passing Multiple Records from one form to another through Args in Dynamics Ax 2012

The Scenario is when I select multiple grids in Form A, those records will be passed to FormB and there FormB will received the all those records and filter it and will show.

Step 1: Make one SampleTable which has three fields named (SIno, name, AddressCity).
Step 2: Make FormA with datasource as SampleTable and drag the datasource fields into the design Grid.
Step 3: Drag one button and override the click method and write the following code.
step 4: Make one Display menuitem of FormB.


void clicked()
{
int recordsCount;
SampleTable _sampleTable;
container con;
Args args;
str multiSelectString;
;
args = new Args();
recordsCount = SampleTable_ds.recordsMarked().lastIndex(); // gets the total records selected
_sampleTable = SampleTable_ds.getFirst(1);
while (_sampleTable)
{
// storing recid of selected field in container
con = conIns(con,1,_sampleTable.RecId);
// converting container to string with comma separated
multiSelectString = con2Str(con,’,');

_sampleTable = SampleTable_ds.getNext(); // moves to next record
}
// passing string
args.parm(multiSelectString);
// calling menu item
new MenuFunction(menuitemDisplayStr(FormBMenuItem), MenuItemType::Display).run(args);
}

step 5: Make FormB with datasource as same table for which you take for Form A i.e., SampleTable and drag the fields in to the
Grid of design part.
step 6: write the following code in to the init method of FormB.

public void init()
{
container con;
int i;
str multipleRecords;
super();
// getting string value from caller
multipleRecords = element.args().parm();
// string to container
con = str2con(multipleRecords,”,”);
// for sorting
for(i = 1;i<= conLen(con) ;i++)
{
SampleTbl_ds.query().dataSourceTable(Tablenum(SampleTbl)).addRange(fieldNum(SampleTbl,RecId)).value(SysQuery::value(conPeek(con,i)));
}
}

Passing Args from one Form to another Form in Dynamics Ax 2012

Args concept in dynamics ax is awesome. one can easily pass arguments from one Form to another Form with very less effort. Here, i am going to demonstrate how to pass Arguments from Form to Form. The Scenario is when I select one grid in Form A, that record will be passed to Form B and there Form B will received the whole record and filter it and will show.


Step 1: Make one SampleTable which has three fields named (SIno, name, AddressCity).

Step 2: Make FormA with datasource as SampleTable and drag the datasource fields into the design Grid.

Step 3: Drag one button and override the click method and write the following code.

void clicked()
{
Args args;
FormRun formRun;
;
super();
args = new args(formstr(FormB)); // sending Args(record) to FormB
args.record(SampleTable);
formrun = classfactory.formrunclass(args);
formrun.init();
formrun.run();
formrun.wait();
formrun.detach();

}






step 4: Make FormB with datasource as same table for which you take for Form A i.e., SampleTable and drag the fields in to the
Grid of design part.



step 5: write the following code in to the init method of FormB.

public void init()
{
SampleTable _sampleTable;
super();
_sampleTable = element.args().record();
SampleTable_ds.query().dataSourceTable(Tablenum(SampleTable)).addRange(fieldNum(SampleTbl,RecId)).
value(SysQuery::value(_sampleTable.Recid));
}

Thursday, January 30, 2014

Creating New Financial Dimension – Dynamics AX 2012


Financial Dimension – Dynamics AX 2012 


New Financial Dimension

1.       First create the new code. Go to General Ledger > Setup > Financial dimensions > Financial dimensions and create a new financial dimension.
2.        After that there you’ll notice that the ‘Use values from’ can be set to as above, but also there is a long list existing dimensions as well.



3.       If you use an existing field, then you won’t have to create any values for your new financial dimension – the system will use the values already present in the database.

4.       If you’re going to use ‘Custom values’ for your new financial dimension the next step is to define the valid values which may be entered. Go to General ledger > Setup > Financial dimensions > Financial dimensions > Financial dimension values:

5.       To set an entity to be dimensionable,
6.       Create a view as directed below, Also, to integrate with the dimensions framework when deleting or renaming the natural key of the backing entity, you must write custom code on the backing table’s delete method, and also on either the update or renamePrimaryKey method. See CustTable for an example of the pattern these methods must follow 


7.       The view name must be DimAttribute[yourentityname]. For example, DimAttributeProjGrant.
8.       The view must contain a root data source named BackingEntity that points to your backing table to identify a surrogate key and natural key.
9.       The view must contain the following fields named exactly as follows: • Key – Must point to the backing entity’s SK field. For example, an int64 RecId field. • Value – Must point to the backing entity’s NK field. For example, a str30 GrantId field. • Name – Must point to the source of an additional description for the entity. For example, a str60 Description field


List of dimensionable entities are also cached on both the client and server, so we have to execute the following line of code within a job in order to load the new dimension:

static void ClearDimensionCache(Args _args)
{
    DimensionCache::clearAllScopes();
info(‘done’);

}

To add the newly created Dimension to any form, we need to follow below link that explains it very well


Monday, January 6, 2014

Filtering drop down list based on another drop down in SSRS Reports

Senario:
Filter Customer Account’s based on Customer Group.

Steps:
1.      Create a Query CustReportDemo
Add CustTable as Datasource to Query.






Select fields in the properties option Dynamics == Yes.

2.      Now we have to move to classes, as per the requirement we have to create 2 classes.
3.      DataProvider Class, Contract Class, UI Builder class.
4.      So, Here is what we need to do.
First create a contract class as (I am hoping) we already know. Here I am using an example of Customer which will be filtered by Customer group. The code of class declaration will be:

[
DataContractAttribute
]
public class custReportContract

{
    CustGroupId custGroup;
    AccountNum cust;

}

Now creating 2 new methods for getting and setting these parameters. 1 for cust group
[
DataMemberAttribute('CustGroup'),
SysOperationLabelAttribute(literalstr("@SYS11904"))
]
public CustGroupId parmCustGroup(CustGroupId _custGroup= custGroup)
{
    custGroup = _custGroup;
    return custGroup;
}

And the other one for customer
[
DataMemberAttribute('Cust'),
SysOperationLabelAttribute(literalstr("@SYS313797"))
]
public AccountNum parmCust(AccountNum _cust= cust)
{
    cust = _cust;
    return cust;
}

Your screen will look like this:

  
Nothing new in it. We all know it (I guess). Moving forward and now we are creating another class for UI builder.
Create this new class and on the class declaration method, type the following code
public class custReportUIBuilder extends SysOperationAutomaticUIBuilder
{
}

your screen will look like this

Now we have to create 2 dialog boxes. 1 for customer group and customer each. To do this type the following code.
    DialogField dialogCustGroup;
    DialogField dialogCust;

We also have to define our contract class here, so declare the contract class
    custReportContract contract;

so, the class declaration method will look like this:
UI Builder Class:

public class custReportUIBuilder extends SysOperationAutomaticUIBuilder
{
    DialogField dialogCustGroup;
    DialogField dialogCust;

    custReportContract contract;
}
Now, we have to draw the dialog boxes. For this reason, we will create another method of build and type the following code In it.

public void build()
{
    Dialog      dialogLocal = this.dialog();
    custReportContract contract = this.dataContractObject();
   
    dialogLocal.addGroup("Customer");
    this.addDialogField(methodStr(custReportContract,parmCustGroup), contract);
    this.addDialogField(methodStr(custReportContract,parmCust), contract);

}

Now that we created the build method, let’s move into filling the cust group drop down with the table CustGroup. We’ll create another method for lookup and type the following code in it.

public void lookupCustGroup(FormStringControl _control)
{
    Query query = new Query();
    SysTableLookup sysTablelookup;

    sysTablelookup =SysTableLookup::newParameters(tableNum(CustGroup),_control);
    sysTablelookup.addLookupfield(fieldNum(CustGroup,CustGroup));
    sysTablelookup.addLookupfield(fieldnum(CustGroup,Name));

    query.addDataSource(tableNum(CustGroup));

    sysTablelookup.parmQuery(query);
    sysTablelookup.performFormLookup();
}


We need to create another method so that when user selects any record from cust group drop down, the customer drop down will be filtered with that value, for this reason we will select the modified event of cust group and then type the code:
public boolean custGroupModified(FormStringControl _control)
{
    dialogCustGroup.value(_control.valueStr());
    dialogCust.value('');
    return true
}

Ok now we will create the lookup method for customer. Here is the code
public void lookupCust(FormStringControl _control)
{
    Query query = new Query();
    SysTableLookup sysTablelookup;

    sysTablelookup =SysTableLookup::newParameters(tableNum(CustTable),_control);
    sysTablelookup.addLookupfield(fieldNum(CustTable,AccountNum));
    sysTablelookup.addLookupfield(fieldnum(CustTable,Party));

    query.addDataSource(tableNum(CustTable));
    query.dataSourceTable(tableNum(CustTable)).addRange(fieldNum(CustTable, CustGroup)).value(dialogCustGroup.value());
   
    sysTablelookup.parmQuery(query);
    sysTablelookup.performFormLookup();
}

Note that I filtered the cust query with the value selected in cust group drop down
    query.dataSourceTable(tableNum(CustTable)).addRange(fieldNum(CustTable, CustGroup)).value(dialogCustGroup.value());

we have almost completed our code for lookups and their filters. Now we will bind our dialog boxes with the contract class params and also override the modified method of cust group with the method we just wrote. To do this we will create another method for postBuild. Here we go

public void postBuild()
{
    super();
    // From binding info, get the dialog field for racecode attribute and add button
    dialogCustGroup = this.bindInfo().getDialogField(
                         this.dataContractObject(),
                         methodStr(custReportContract,parmCustGroup));
    if (dialogCustGroup)
    {
     dialogCustGroup.lookupButton(2);
    }

    // register override method for lookup cust Group
    dialogCustGroup.registerOverrideMethod(methodStr(FormStringControl, lookup),methodStr(custReportUIBuilder, lookupCustGroup), this);
    // register override method for modified
    dialogCustGroup.registerOverrideMethod(methodStr(FormStringControl, modified),methodStr(custReportUIBuilder, custGroupModified), this);
   
    //binding info for customer drop down
    dialogCust = this.bindInfo().getDialogField(
                         this.dataContractObject(),
                         methodStr(custReportContract,parmCust));
   
    // register override method for lookup customer
    dialogCust.registerOverrideMethod(methodStr(FormStringControl, lookup),methodStr(custReportUIBuilder, lookupCust), this);
   
    if (dialogCust)
    {
        dialogCust.lookupButton(2);
    }

}

We may have to create some other methods as well in order to functioning your code properly. They are getFromDialog, initializeFields and postRun. Create three new methods each for getFromDialog, initializeFields and postRun and copy the following code to them

GetFromDialog:


public void getFromDialog()
{
    contract = this.dataContractObject();
    super();
}

InitializeFields:

public void initializeFields()
{
    contract = this.dataContractObject();
}

PostRun
public void postRun()
{
    super();
}

We are done. But wait one last thing, open your contract class and in the class declaration method, reference your UI builder class just below the DataContractAttribute. Your code will become:
Contract Class

ClassDeclaration
[
    DataContractAttribute,
    SysOperationContractProcessingAttribute(classStr(custReportUIBuilder))
]
public class custReportContract

{
    CustGroupId custGroup;
    AccountNum cust;

}
 We are now done. In this post we have tried to filter our single value drop down based on another drop down. In the next post we will try to repeat the same process for multi value drop down list.
Thank you all
Here is the screen shot of what we just did






DataProvider Class:
To fetch information from TmpTable and print data in to report, we have to update in ProcessReport Method.

ClassDeclaration:
 [
    SRSReportQueryAttribute(queryStr(CustReport)),
    SRSReportParameterAttribute(classStr(custReportContract))
]
public class custreportDP extends SRSReportDataProviderBase
{
    CustreportTmp           custreportTmp;
}

CustReportTmp

[ SRSReportDataSetAttribute(tableStr(CustreportTmp))
]
public CustreportTmp custreportTmp()
{
    select * from custreportTmp;
    return custreportTmp;
}


ProcessReport

public void processReport()
{
    QueryRun                    qr;
    QueryBuildRange             qbr;
    Query                       query;
    CustTable                   custTable;
    CustGroup                   custGroup;

    // Get a reference to the contract for this report. The relevant contract class is
    // defined by the SRSReportParameterAttribute used in the class declaration.
    custReportContract          contract  = this.parmDataContract() as custReportContract;
    boolean                     addLine;
    query = this.parmQuery();

    if(contract.parmCustGroup() && contract.parmCust())
    {
        query.dataSourceNo(1).clearRanges();
        qbr = query.dataSourceNo(1).addRange(fieldNum(CustTable,custGroup));
        qbr.value(contract.parmCustGroup());
        qbr = query.dataSourceNo(1).addRange(fieldNum(CustTable,AccountNum));
        qbr.value(contract.parmCust());
        qr = new QueryRun(query);
       while(qr.next())
                {
                    CustTable = qr.get(tableNum(CustTable));
                    custreportTmp.clear();
                    custreportTmp.AccountNum = CustTable.AccountNum;
                    custreportTmp.CustGroup = CustTable.CustGroup;
                    custreportTmp.insert();
                }
    }
    else if(contract.parmCustGroup())
    {
        qbr = query.dataSourceNo(1).addRange(fieldNum(CustTable,custGroup));
        qbr.value(contract.parmCustGroup());
        qr = new QueryRun(query);
        while(qr.next())
                {
                    CustTable = qr.get(tableNum(CustTable));
                    custreportTmp.clear();
                    custreportTmp.AccountNum = CustTable.AccountNum;
                    custreportTmp.CustGroup = CustTable.CustGroup;
                    custreportTmp.insert();
                }
    }
    else if(contract.parmCust())
    {
        qbr = query.dataSourceNo(1).addRange(fieldNum(CustTable,AccountNum));
        qbr.value(contract.parmCust());
        qr = new QueryRun(query);
        while(qr.next())
                {
                    CustTable = qr.get(tableNum(CustTable));
                    custreportTmp.clear();
                    custreportTmp.AccountNum = CustTable.AccountNum;
                    custreportTmp.CustGroup = CustTable.CustGroup;
                    custreportTmp.insert();
                }
    }

    else if (!contract.parmCust() && !contract.parmCustGroup())
    {
        qr = new QueryRun(query);
        while(qr.next())
                {
                    CustTable = qr.get(tableNum(CustTable));
                    custreportTmp.clear();
                    custreportTmp.AccountNum = CustTable.AccountNum;
                    custreportTmp.CustGroup = CustTable.CustGroup;
                    custreportTmp.insert();
                }
    }
}


OutPut:
Senario1:
Selecting CustomerGroup In lookup as 10 , Customers should get filter based on the custgroup.







After selecting Customer Account as 1101. Final report is




Senario 2:
Selecting Only Customer Group as “10”



Senario3:
Selecting only Customer Account as “1101”



Senario 4:
Customer Account & Customer Group is Null.