Nov 20, 2012

PO creation on Button click

The following is to create the  PO for the journals on the button click event for the selected posted journals on ledgerJournalTable form which has TradeAgreement

Step 1 : Created one field TradeAgreement  (TradeAgreement is associated with items on its master form) on LedgerJournalTable.

Step 2  : Create one edit method on LedgerJournalTable forms datasource Level to select the journals for PO creation.

The following is the method


public edit Noyes createPO(boolean _set, LedgerJournalTable _table, NoYes _value)
{
    LedgerJournalTable    updatePOCreation;
    ; 
    LedgerJournalTable_ds.allowEdit(true);
    if (_set)
    {
        if(_table.Posted  == Noyes::No)
        {
            throw error("Please choose posted record");
        }
        if(_value)
        { 
            setRecordId.add(_table.RecId);
            _value =  NOYes::Yes;
        } 
        else
        {
            setRecordId.remove(_table.RecId);
            _value =    NOYes::Yes;
        }
    }
    return setRecordId.in(_table.RecId);
}


Drag this method on to the Design --> Overview --> Grid

Step 3 :  Create a button and call the Class (which has PO Creation code) on its click() for selected journals
 
void clicked()
{
    SS_POCreate                     creationOfPO;
    boolean                               created;
    LedgerJournalTable              _ledgerJournalTable;
    SetEnumerator                      setRetention, updateRetention;
    SSRetentionReversal             RetentionReversal;
    ;

    super();
    creationOfPO    =   new SS_POCreate();
    RetentionReversal   =   SSRetentionReversal::construct();
    setRetention            =    Set::create(setRecordId.pack()).getEnumerator();
    updateRetention     = Set::create(setRecordId.pack()).getEnumerator();
    if(!setRecordId.empty())
    {

        ttsbegin;
        while(setRetention.moveNext())
        {
            select _ledgerJournalTable where  _ledgerJournalTable.RecId == setRetention.current();
            creationOfPO.createPO(_ledgerJournalTable.JournalNum);
            created  = true;
        }
        ttscommit;
    }
    if(created)
    {
        info("PO's created sucessfully");
    }
    else
    {
        info("PO's creation failed");
    }
}

Step 4 : The PO creation class should be as following

class SS_POCreate
{
    PurchId         purchaseId;
    PurchTable      purchaseTable;
    PurchLine       purchaseLines;
    boolean         created;
}


Void  createPO(LedgerJournalId     _journal)
{
    SS_TradeAgreementId     tradeAgreementId;
    PurchTable              purchTableCur;
    ;
    tradeAgreementId  = LedgerJournalTable::find(_journal).SS_TradeAgreementId;

    select purchaseTable where purchaseTable.SS_JournalNo == _journal;

    if(purchaseTable.RecId)
    {
        throw error (strfmt("PO is already created for the Journal : %1 , so unable to create again for the same",_journal));
    }
    else
    {
       ttsbegin;
        if(tradeAgreementId)
        { 
            purchaseTable.PurchId        = NumberSeq::newGetNumFromCode(NumberSequenceReference::find(extendedTypeNum(purchid)).NumberSequence,true,false).num(); 

            purchaseTable.OrderAccount   = SS_CategoryTradeAgreement::find(tradeAgreementId).Vendor;
            purchaseTable.InvoiceAccount = SS_CategoryTradeAgreement::find(tradeAgreementId).Vendor;
            purchaseTable.PurchaseType   = PurchaseType::Purch;
            purchaseTable.PurchStatus    = PurchStatus::Backorder;
            purchaseTable.PurchTypeCode  = "Stock";
            purchaseTable.initFromVendTable(VendTable::find(SS_CategoryTradeAgreement::find(tradeAgreementId).Vendor));
            purchaseTable.PurchOrderType = PurchOrderType::Regular;
            purchaseTable.SS_JournalNo   = _journal;
            purchaseTable.CurrencyCode   = SS_CategoryTradeAgreement::find(tradeAgreementId).Currency;
            purchaseTable.insert();

            if(purchaseTable.PurchId)
            {
               this.createPOLines(purchaseTable.PurchId ,tradeAgreementId);

            }
            ttscommit;

        }
    }
}

void createPOLines(PurchId   _purchId ,SS_TradeAgreementId   _tradeAgreementId)
{
    InventDim             _inventDim;
    InventItemLocation    inventItemLocation;
    Inventlocation        inventLocation;
    InventTable           inventTable;
    ;
    purchaseLines.clear();
    purchaseLines.PurchId    = _purchId;
    purchaseLines.ItemId     = SS_CategoryTradeAgreement::find(_tradeAgreementId).ItemId;
    inventTable              = inventTable::find(purchaseLines.ItemId);
    purchaseLines.PurchUnit  = inventTable.purchUnitId();

    purchaseLines.PurchQty              = 1;
    purchaseLines.PurchPrice            = SS_CategoryTradeAgreement::find(_tradeAgreementId).Rate;

    purchaseLines.CurrencyCode          = SS_CategoryTradeAgreement::find(_tradeAgreementId).Currency;
    purchaseLines.PurchStatus           = PurchStatus::Backorder;
    purchaseLines.PurchaseType          = PurchaseType::Purch;
    purchaseLines.LineAmount            = purchaseLines.PurchQty * purchaseLines.PurchPrice;
    purchaseLines.LineNum               = PurchLine::lastLineNum(_purchId) + 1.0;


    select firstonly InventItemLocation
        where InventItemLocation.ItemId == purchaseLines.ItemId
        &&   InventItemLocation.inventDimId != "AllBlank";

    if(InventItemLocation.RecId)
    {
          _inventDim.InventSiteId    = InventLocation::find(InventDim::find(InventItemLocation.inventDimId).InventLocationId).InventSiteId;
          _inventDim.InventLocationId = InventDim::find(InventItemLocation.inventDimId).InventLocationId;

    purchaseLines.InventDimId =   InventDim::findOrCreate(_inventDim).inventDimId;
    purchaseLines.insert();
    }
    else
    {
    throw error(strfmt("Warehouse item setup could not find for the item :%1 ",purchaseLines.ItemId));
    }
}

static  SS_POCreate construct()
{
    return new SS_POCreate();
}











Nov 16, 2012

Validation on FromDate and ToDate


public boolean validateWrite()
{
    boolean ret;
    SS_CategoryTradeAgreement      categoryTradeAgreement;
    ;

    ret = super();

    if(this.ToDate < this.FromDate)
        ret = checkFailed("Todate should be greater than or equal to Fromdate");

    while select categoryTradeAgreement where  categoryTradeAgreement.Category == this.Category
                                            && categoryTradeAgreement.Vendor == this.Vendor
                                            && categoryTradeAgreement.RecId != this.RecId
                                            && (( categoryTradeAgreement.FromDate <= this.FromDate && categoryTradeAgreement.ToDate >= this.FromDate)
                                                       ||(categoryTradeAgreement.FromDate <= this.ToDate   && categoryTradeAgreement.ToDate >= this.ToDate))
    {
    ret = checkfailed(strfmt("Duplicate Entries are not allowed - Same record is there for Vendor - %1 with Category %2 of period %3 - %4" ,
                         categoryTradeAgreement.Vendor,categoryTradeAgreement.Category,categoryTradeAgreement.FromDate,categoryTradeAgreement.ToDate));
    break;
    }


    return ret;
}

Join by Query

static void CustTableSales(Args _args)
{
    Query                             query;
    QueryRun                       queryrun;
    QueryBuildDataSource     qbds1;
    QueryBuildDataSource     qbds2;
    QueryBuildRange             qbr1;
    QueryBuildRange             qbr2;
    CustTable                        custTable;
    ;
    query     = new query();
    qbds1    =   query.addDataSource(tablenum(CustTable));
    qbds1.addSortField(fieldnum(custTable,AccountNum),Sortorder::Descending);
    qbr1    = qbds1.addRange(fieldnum(custTable,custGroup));
    qbr1.value(queryvalue('10'));

    qbr2     =  qbds1.addRange(fieldnum(custTable,Blocked));
    qbr2.value(queryvalue(CustVendorBlocked::No));
    qbds2   = qbds1.addDataSource(tablenum(SalesTable));
    qbds2.relations(false);
    qbds2.joinMode(joinmode::ExistsJoin);
    qbds2.addLink(fieldnum(CustTable,AccountNum),fieldnum(SalesTable,CustAccount));
    queryrun    = new queryrun(query);

    while(queryrun.next())
    {
    custTable   = queryrun.get(tablenum(custTable));
    info(strfmt("%1 - %2",custtable.AccountNum,custTable.Name));
    }
}

Oct 30, 2012

How to get caller form name ?


This is an example for enabling and disabling of button1 and button2  on basis of caller form

Public void buttonEnable()
{
    UserGroupList           userGroupList,userGroupList1;
    ProjParameters          projParameters;
    formRun                    caller;
    ;
    caller = element.args().caller(); // caller form

    if(caller.args().name() == formStr(ProjTable)) // caller form name
    {
        projParameters = ProjParameters::find();
        
       // Checking that the CurUserId() is there of one particular group or not

        Select userGroupList where userGroupList.UserId == curUserId()
                                   && userGroupList.groupId == projParameters.SalesAcceptanceChangeOrder;
        if(userGroupList)
        {
            Button1.enabled(true);
        }
        else
        {
            Button1.enabled(false);
        }
        Select userGroupList1 where userGroupList1.UserId == curUserId()
                                   && userGroupList1.groupId == projParameters.CommercialAcceptanceChangeOrder;
        if(userGroupList1)
        {
            Button2.enabled(true);
        }
        else
        {
            Button2.enabled(false);
        }
    }
    if(caller.args().name() == formStr(ProjQuoteTable))
    {
        projParameters = ProjParameters::find();

        Select userGroupList where userGroupList.UserId == curUserId()
                                   && userGroupList.groupId == projParameters.SalesAcceptanceQtn;
        if(userGroupList)
        {
            Button1.enabled(true);
        }
        else
        {
            Button1.enabled(false);
        }
        Select userGroupList1 where userGroupList1.UserId == curUserId()
                                   && userGroupList1.groupId == projParameters.CommercialAcceptanceQtn;
        if(userGroupList1)
        {
            Button2.enabled(true);
        }
        else
        {
            Button2.enabled(false);
        }
    }

}

Oct 23, 2012

How to filter the records in dialog field values ?


The following example class is to filter the records in a dialog fields

class TestDialogFields
{
    Dialog                       dialog;   
    DialogField              emplIdField;
}

Dialog showDialog()
{
    FormRun        formRun;
    ;
    dialog         = new Dialog('Dialog fields test');   
    emplIdField = dialog.addField(typeId(emplid));
    dialog.run(true);
    dialog.formRun().controlMethodOverload(true);
    dialog.formRun().controlMethodOverloadObject(this);
    return  dialog;
}

public void Fld1_1_lookup()
{
    FormStringControl        control               = dialog.formRun().controlCallingMethod();
    SysTableLookup          sysTableLookup =  SysTableLookup::newParameters(tablenum(EmplTable), control);
    Query                         query                = new Query();
    QueryBuildDataSource                          queryBuildDataSource;
    EmplTable                                            EmplTable;
    ;
   
    sysTableLookup.addLookupfield(fieldnum(EmplTable, EmplId));
    sysTableLookup.addLookupfield(fieldnum(EmplTable,EmplIdentNumber ));
    queryBuildDataSource = query.addDataSource(tablenum(EmplTable));
    queryBuildDataSource.addRange(fieldnum(EmplTable,EmplId)).value(queryRange("1000","2000"));
    sysTableLookup.parmQuery(query);
    sysTableLookup.performFormLookup();
}

public static void main(Args args)
{
     TestDialogFields testDialogFields = new TestDialogFields();
     ;
     testDialogFields.showDialog();
}

How to open a a form on button click ?


void clicked()
{
    Menufunction       menufunction ;
    Args                    args = new Args();
    FormRun              formRun;
    ;
    
    if(MyTable.StatusId == " ")
    {
        throw error("Please fill the StatusId of the record ");
    }
    else
    {
    args.record(MyTable);
    menufunction  = new Menufunction(menuitemdisplaystr(MyTrans),menuItemType::Display);
    formRun         = menufunction.create(args);
    formRun.run();
    formRun.wait(true);
  
      }
   
}

Sep 24, 2012

Lookup

The process of building a lookup form.

 1) Create a table with code, description fields
 2) Create a form with the fields.
 3) Create an EDT with table relation
 4) Create the display menuitem of the builded form
 5) Give the MenuItem name in the table's formref property.
 6) Use the EDT where u want to show the lookup form.

Sep 20, 2012

Data update in Ax by excel


Below class is to update the LedgerJournalTrans Check number



class CITBRSCheckUpload extends Runbase
{
    DialogField                 dialogFilename;
    FilenameOpen                fileName;


    #define.CurrentVersion(1)
    #localmacro.CurrentList
        filename
    #endmacro
}


protected Object dialog()
{
    DialogRunBase   dialog = new DialogRunBase("Import Check Number", this);

    ;
    dialogFilename = dialog.addField(typeId(FilenameOpen));
    dialog.filenameLookupFilter(["@SYS28576","*.xlsx"]);
    dialog.filenameLookupTitle("Upload from Excel");
    dialogFilename.value(filename);
    dialog.caption("Excel Upload");
    return dialog;
}


public boolean getFromDialog()
{
;
    filename        = dialogFilename.value();

    if(!filename)
    {
    throw error("@SYS112406");
    }
    return true;
}


Public void ImportDatafromExcel()
{
    SysExcelApplication application;
    SysExcelWorkbooks   workbooks;
    SysExcelWorkbook    workbook;
    SysExcelWorksheets  worksheets;
    SysExcelWorksheet   worksheet;
    SysExcelCells       cells;
    COMVariantType      type;
    int                 row;
    str c,test;
    BankAccountTrans    BankAcntTrans;
    LedgerJournalTrans  journalTrans;
    VendParameters      vendParms;
    Voucher             ledgerTransVoucher;
    Date                ledgerTransDate;
    BankChequeNum       ledgerTransChequeNum;
    boolean             temp;

    ;
    temp    = false;
    row     = 2;

    application = SysExcelApplication::construct();
    workbooks = application.workbooks();
    workbooks.open(fileName,0,true);

    try
    {
        workbooks.open(filename,0,0,2);
    }
    catch (Exception::Error)
    {
        throw error("File cannot be opened.");
    }

    workbook = workbooks.item(1);
    worksheets = workbook.worksheets();
    worksheet = worksheets.itemFromNum(1);
    cells = worksheet.cells();
    select  vendParms;

    if(vendParms.CITPaymentVoucher ==0 ||vendParms.CITASODate ==0 ||vendParms.CITUTRNumber == 0)
        throw error("Excel template mapping in AP Parameter are not done");

    //do
    while(cells.item(row,1).value().toString()!= "VT_EMPTY")
    {

        ledgerTransVoucher = cells.item(row,vendParms.CITPaymentVoucher).value().bStr();
        ledgerTransDate = cells.item(row, vendParms.CITASODate).value().date();
        ledgerTransChequeNum = cells.item(row, vendParms.CITUTRNumber).value().bStr();
        if(ledgerTransVoucher == " ")
            info("For row "+ int2str(row) + "Voucher is blank");
        if(!ledgerTransDate)
            info("For row "+ int2str(row) + "Transaction Date is blank");
        select  forupdate journalTrans where journalTrans.Voucher == ledgerTransVoucher
                                 && journalTrans.TransDate == ledgerTransDate;
        {
            if(journalTrans)
            {

               if(journalTrans.BankChequeNum == " ")
               {
                ttsbegin;
                journalTrans.BankChequeNum = ledgerTransChequeNum;
                journalTrans.update();
                select forupdate BankAcntTrans where BankAcntTrans.Voucher == ledgerTransVoucher
                                                    && journalTrans.TransDate == ledgerTransDate;
                {
                BankAcntTrans.ChequeNum = ledgerTransChequeNum;
                BankAcntTrans.update();
                }
                temp    = true;
                ttscommit;
                }
                else
                {
                 info("For " +ledgerTransVoucher +" No."+  strfmt(" Check number is already there. So you cannot update that "));
                }

            }

        }
        row++;

       }
    //while(cells.item(row,1).value().toString()!= "VT_EMPTY");
   // while (type != COMVariantType::VT_EMPTY);

    if(temp == true)
    {
    info(strfmt("Uploaded successfully."));
    }
    else
    {
    info(strfmt("Upload fail."));
    }

    application.quit();
}
public container pack()
{
    ;
    return [#CurrentVersion,#CurrentList];
}

public boolean unpack(container _packedClass)
{
    Integer     version     = conpeek(_packedClass,1);
    ;
    switch (version)
    {
    case #CurrentVersion:
    [version,#CurrentList]      = _packedClass;
    break;

    default :
    return false;
    }
    return true;
}

public static CITBRSCheckUpload construct()
{
    return  new  CITBRSCheckUpload();
}

public static void main(Args _args)
{
    CITBRSCheckUpload   ExcelUpload = CITBRSCheckUpload::construct();
    ;
    if (ExcelUpload.prompt())
    {
        //Call function ExcelUpload.
        ExcelUpload.ImportDatafromExcel();

    }
}


Jun 14, 2012

What is DLL in AX ?


What is a DLL?

     A dynamic-link library (DLL) file is an executable file that allows programs to share code and other resources necessary to perform particular tasks.

     A DLL provides one or more particular functions. Programs accesses these functions by creating either a static or dynamic link to the DLL. A static link remains constant during program execution while a dynamic link is created by the program as needed.

     A DLL can be used by several applications at the same time. Some DLLs are provided with the Windows operating system and available for any Windows application. Other DLLs are written for a particular application and are loaded with the application.

     DLL files usually end with the extension .dll,.exe., drv, or .fon.

     Kernel.exe, User.exe and Gdi.exe are examples of DLLs with .EXE extensions. They provide code, data or routines to programs running in the Windows operating system.

     DLLs may be found in the Windows directory, Windows\System directory or in an program's directory.


Field level Modified()

The following code is for to compare the  modified field value on form level :

Go to form Datasource(My datasource is JpSampleTable) field level and override the field's modified() as -


public void modified()
{
    if(JpSampleTable.JoinDate < JpSampleTable.orig().JoinDate)
        info("Modified date " +strfmt("%1",JpSampleTable.orig().JoinDate)+ " is less than "+strfmt("%1",JpSampleTable.JoinDate));
    super();
}



Creating a form for lookup

The following code is to performing form lookup for a field on another form..

Step 1 : Create a form (EmplIdLookupForm) with the required fields(Lookup form)
 
  - Override the form level init() and run() as

void init()
{
    ;

    super();

    element.selectMode(emplTable_EmplId);
}

public void run()
{
    FormStringControl callingControl = SysTableLookup::getCallerStringControl(element.args());
    boolean filterLookup;
    ;

    filterLookup = SysTableLookup::filterLookupPreRun(callingControl, emplTable_EmplId, emplTable_ds);

    super();

    SysTableLookup::filterLookupPostRun(filterLookup, callingControl.text(), emplTable_EmplId, emplTable_ds);
}

- Override the forms DataSource Level init() as

void init()
{
    Query   query = new Query();
    ;
    super();

    query.addDataSource(tablenum(EmplTable));

    this.query(query);
}

Step 2 : Override the Lookup caller form field's Lookup() with following code

FormRun formRun;
    Args args;
    ;

    args = new Args(formstr(EmplIdLookupForm));
    args.caller(this);
    formRun = ClassFactory::formRunClassOnClient(args);
    formRun.init();
    this.performFormLookup(formRun);

May 7, 2012

AX Label files

                                                          Label Files 
The term label in Dynamics AX refers to a localizable text resource, used throughout the product as messages to the user, form control labels, column headers,Help text in the status bar, captions on forms, and text on Web forms, to name just a few places. Labels are localizable, meaning that they can be translated into most languages
All text resources are kept in a Unicode-based label file that must have a three-letter identifier. The label file is located in the application folder (Program Files\Microsoft Dynamics AX\50\Application\Appl\Standard) and follows this naming convention:

                                    Ax
The following are two examples, the first showing U.S. English and the second a Danish label file:
Axsysen-us.ALD
Axtstda.ALD
Each text resource in the label file has a 32-bit integer label ID, label text, and an optional label description. The structure of the label file is very simple:
@<Label file identifier>
[Label description]
Below figure shows Label file opened in Microsoft Notepad showing a few labels from the en-us label file
                
             This simple structure allows for localization outside Dynamics AX using third-party tools.
After the localized label files are in place, the user can choose a language in the Options dialog box. When the language is changed, the user must close and restart the Dynamics AX client.
           You can create new label files by using the Label File Wizard, which you access from the Microsoft Dynamics AX drop-down menu by clicking Tools\Development Tools\Wizards\Label File Wizard. The wizard guides you through the steps for adding a new label file or a new language to an existing label file. After you run the wizard, the label file is ready to use.
Note
You can use any combination of three letters when naming a label file, and you can use any label file from any layer. A common misunderstanding is that the label file identifier must be the same as the layer in which it is used. This misunderstanding is caused by the Microsoft label file identifiers. Dynamics AX ships with a SYS layer and a label file named SYS; service packs contain a SYP layer and a label file named SYP. This naming standard was chosen because it is simple, easy to remember, and easy to understand. Dynamics AX doesn’t impose any limitations on the label file name.

The following are tips for working with label files:
  • When naming a label file, choose a three-letter ID that has a high chance of being unique, such as your company’s initials. Don’t choose the name of the layer, such as VAR or USR. Eventually, you’ll likely merge two separately developed features into the same installation, a task that will be more difficult if the label files collide.
  • Feel free to reference labels in the Microsoft-provided label files, but avoid making changes to labels in these label files, because they are updated with each new version of Dynamics AX.

Creating a New Label

You use the Label Editor to create new labels. You can start it using any of the following procedures:
  • Clicking Tools\Development Tools\Label\Label Editor from the Microsoft Dynamics AX drop-down menu
  • Clicking the Lookup Label/Text button on the X++ code editor toolbar
  • Clicking the Lookup button on text properties in the property sheet
The Label Editor (shown in Figure L) allows you to find existing labels. Reusing a label is often preferable to creating a new one. You can create a new label by pressing Ctrl+N or by clicking the New button.
Figure L. Label Editor

In addition to allowing you to find and create new labels, the Label Editor can also show where a label is used. It also logs any changes to each label. 

The following are tips to consider when creating and reusing labels:
  • When reusing a label, make sure that the label meaning is what you intend it to be in all languages. Some words are homonyms, meaning words that have many meanings, and they naturally translate into many different words in other languages. For example, the English word can is both a verb and a noun. The description column describes the intended meaning of the label.
  • When creating new labels, make sure to use complete sentences or other stand-alone words or phrases in each label. Don’t construct complete sentences by concatenating labels with one or few words, because the order of words in a sentence differs from one language to another.

Referencing Labels from X++

           In the MorphX design environment, labels are referenced in the format @<LabelFileIdentifier> <LabelID>. If you don’t want a label reference to automatically convert to the label text, you can use the literalStrfunction. When a placeholder is needed to display the value of a variable, you can use the strFmt function and a string containing %n, where n> = 1. Placeholders can also be used within labels. The following code shows a few examples.
   
// prints: Time transactions
print "@SYS1";

// prints: @SYS1
print literalStr("@SYS1");

// prints: Microsoft Dynamics is a Microsoft brand
print strFmt("%1 is a %2 brand", "Microsoft Dynamics", "Microsoft");


The following are some best practices to consider when referencing labels from X++:
  • You should always create user interface text by using a label. When referencing labels from X++ code, use double quotation marks.
  • You should never create system text such as file names by using a label. When referencing system text from X++ code, use single quotation marks. You can place system text in macros to make it reusable.
Using single and double quotation marks to differentiate between system text and user interface text allows the Best Practices tool to find and report any hard-coded user interface text. 

The MorphX Tools - Debugger


                                                                                      Debugger
        The debugger is a stand-alone application, not part of the Dynamics AX shell like the rest of the tools . As a stand-alone application, the debugger allows you to debug X++ in any of the Dynamics AX components in the following list:
Microsoft Dynamics AX client :

        Click the Microsoft Dynamics AX drop-down menu, point to Tools and then Options. On the Development tab, select When Breakpoint in the Debug Mode list.
Application Object Server (AOS) :

         Open the Microsoft Dynamics AX Server Configuration utility under Start\Administrative Tools. Create a new configuration (if necessary), and select the check box labeled Enable Breakpoints To Debug X++ Code Running On This Server. 

        For Batch jobs, open the Microsoft Dynamics AX Server Configuration utility under Start\Administrative Tools. Create a new configuration (if necessary), and select the check box labeled Enable Global Breakpoints To Debug X++ Code Running In Batch Jobs.

Enterprise Portal and Business Connector:

        Open the Microsoft Dynamics AX Configuration utility under Start\Administrative Tools. Select one of two check boxes on the Developer tab: Enable User Breakpoints For Debugging Code Running In The Business Connector or Enable Global Breakpoints For Debugging Code Running In The Business Connector Or Client. The latter is useful for debugging incoming Web requests.

Note : Do not enable any of the debugging capabilities in a live environment. If we do, execution will stop when it hits a breakpoint, and users will experience a hanging client.

By pressing F9 we can set or remove " Breakpoint ".
You can enable or disable a breakpoint by pressing Ctrl+F9. For a list of all breakpoints, press Shift+F9.

                                                           Debugger Interface

        The main window in the debugger initially shows the point in the code where a breakpoint was hit. We can control execution one step at a time while variables and other aspects are inspected. Figure 1 shows the debugger opened to a breakpoint with all the windows enabled.
Figure 1. Debugger with all windows enabled

        In the following subsections, we briefly describe the debugger’s various windows and some of its other features.
Main Window :
       The main debugger window shows the current X++ code. Each variable has a ScreenTip that reveals its value. You can drag the next-statement pointer in the left margin. This pointer is particularly useful if the execution path isn’t what you expected or if you want to repeat a step.
Variables Window :
        In this window, local, global, and member variables are shown. Local variables are variables in scope at the current execution point. Global variables are the global classes that are always instantiated: Appl,InfologClassFactory, and VersionControl. Member variables make sense only on classes, and they show the class member variables.
     The Variables window shows the name, value, and type of each variable. If a variable is changed during execution stepping, it is marked in red. Each variable is shown associated with a client or server icon. You can modify the value of a variable by double-clicking the value.

Tip :  As a developer, we might want to provide more information in the value field than what is provided by default. For a class, the defaults are New and Null. You can change the defaults by overriding the toString method. If your class doesn’t explicitly extend object (the base class of all classes), you must add a new method named toString, returning str and taking no parameters, to implement this functionality.
   
Call Stack Window :
      
       The Call Stack window shows the code path followed to arrive at a particular execution point. Clicking a line in the Call Stack window opens the code in the Code window and updates the local Variables window. A client or server icon indicates the tier on which the code is executed.
Watch Window :
     In the Watch window, you can inspect variables without the scope limitations of the Variables window. You can drag a variable here from the Code window or the Variables window.
    The Watch window shows the name, value, and type of the variables. Five different Watch windows are available. You can use these to group the variables you’re watching in the way that you prefer.
Breakpoints Window :
      The Breakpoints window lists all your breakpoints. You can delete, enable, and disable the breakpoints via this window.
Output Window :
       The Output window shows the traces that are enabled and the output sent to the Infolog application framework. The Output window includes the following pages:
  • Debug You can instrument your X++ code to trace to this page by using the printDebug static method on the Debug class.
  • Infolog This page contains messages in the queue for the Infolog.
  • Database, Client/Server, and ActiveX Trace Any traces enabled on the Development tab in the Options dialog box appear on these pages.
Status Bar :
        The status bar at the bottom of the debugger offers the following important context information:
  • Current user The ID of the user who is logged on to the system. This information is especially useful when you are debugging incoming Web requests.
  • Current session The ID of the session on the AOS.
  • Current company accounts The ID of the current company accounts.
  • Transaction level The current transaction level. When reaching zero, the transaction is committed.
Debugger Shortcut Keys
Table lists the most important shortcut keys available in the debugger.

 Debugger Shortcut Keys

ActionShortcutDescription
RunF5Continue execution
Stop debuggingShift+F5Break execution
Step overF10Step over next statement
Run to cursorCtrl+F10Continue execution but break at the cursor’s position
Step intoF11Step into next statement
Step outShift+F11Step out of method
Toggle breakpointShift+F9Insert or remove breakpoint
Variables windowCtrl+Alt+VOpen or close Variables window
Call Stack windowCtrl+Alt+COpen or close Call Stack window
Watch windowCtrl+Alt+WOpen or close Watch window
Breakpoints windowCtrl+Alt+BOpen or close Breakpoints window
Output windowCtrl+Alt+OOpen or close Output window