AX 2012 R3 Line by line invoicing the sales order using X++ code

static void RB_PostSalesInvoice(Args _args)
{
    SalesTable salesTable;
    SalesFormLetter salesFormLetter;
    Query query;
    QueryRun queryRun;
    QueryBuildDataSource qbds;

    salesTable = SalesTable::find('20001');
    query = new Query(QueryStr(SalesUpdatePackingSlip));
    qbds = query.dataSourceTable(tableNum(SalesLine));

    // Build query range to find those lines which needs to be posted.

    qbds.addRange(fieldNum(SalesLine, SalesId)).value('20001');
    qbds.addRange(fieldNum(SalesLine, SalesStatus)).value(queryValue(SalesStatus::Backorder));
    qbds.addRange(fieldNum(SalesLine, itemId)).value('V12_IF');
    queryRun = new queryRun(query);

    salesFormLetter = SalesFormLetter::construct(DocumentStatus::Invoice);
    salesFormLetter.chooseLinesQuery(queryRun);
    salesFormLetter.update(salesTable);
}

AX 2012 R3 SSRS reports to multi select in parameter and functionality of multivalued filtration for SSRS report dialog

In this walk-through , I will give an overview of multi select lookups with filtration of lookup values based on another multi select lookup.  There was requirement of five parameters for a report including: from dateTo DateProject groupsProject names and customer of selected projects as shown below :
In following sections I will show you the implementation of the multi select lookups step by step:   
1.       Creating UI Builder class
Create a class and extend it with SysOperationAutomaticUIBuilder
class SL_InvoiceDetailsUIBuilder extends SysOperationAutomaticUIBuilder
{
    //Dialog fields declaration
    DialogField                             dfprojGroup, dfprojName, dfcustName, dfFromDate, dfToDate;
    container                               ProjGroupsContainer, ProjIdContainer;
    //Multiselect grid declaration
    SysLookupMultiSelectGrid     msCtrlProjGroups, msCtrlProjNames, msCtrlCustNames;
    SL_InvoiceDetailsContract      contract;
}
Override the build method to add dialog fields as follows:
public void build()
{
 contract               = this.dataContractObject();
dfFromDate          = this.addDialogField(methodStr(SL_InvoiceDetailsContract, parmFromDate), contract);
dfToDate              = this.addDialogField(methodStr(SL_InvoiceDetailsContract, parmToDate), contract);
dfprojGroup         = this.addDialogField(methodStr(SL_InvoiceDetailsContract, parmProjGroups), contract);
dfprojName         = this.addDialogField(methodStr(SL_InvoiceDetailsContract, parmProjNames), contract);
dfcustName         = this.addDialogField(methodStr(SL_InvoiceDetailsContract, parmCustNames), contract);
}
Override the PostBuild method to register the multi select lookups with lookup events as follows:
public void postBuild()
{
    super();
    //fromDate
dfFromDate =     this.bindInfo().getDialogField(this.dataContractObject(), methodStr(SL_InvoiceDetailsContract, parmfromdate));
    // to date
dfToDate  = this.bindInfo().getDialogField(this.dataContractObject(), methodStr(SL_InvoiceDetailsContract, parmtodate));
    //Project Group
 dfprojGroup   = this.bindInfo().getDialogField(contract, methodStr(SL_InvoiceDetailsContract,      parmProjGroups));
 dfprojGroup.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(SL_InvoiceDetailsUIBuilder, ProjGroupLookup), this);
       if (dfprojGroup){
        dfprojGroup.lookupButton(2);
       }
    //Project Names
dfprojName   = this.bindInfo().getDialogField(contract, methodStr(SL_InvoiceDetailsContract, parmProjNames));
dfprojName.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(SL_InvoiceDetailsUIBuilder, ProjNamesLookup), this);
      if (dfprojName){
        dfprojName.lookupButton(2);
      }
    //Customers Name
dfcustName   = this.bindInfo().getDialogField(contract, methodStr(SL_InvoiceDetailsContract, parmCustNames));
dfcustName.registerOverrideMethod(methodStr(FormStringControl, lookup), methodStr(SL_InvoiceDetailsUIBuilder, CustNamesLookup), this);
      if (dfcustName){
        dfcustName.lookupButton(2);
     }
}
There are three multi select lookups Project Groups, Project Names and Customer names, the implementation of Project Group lookup is as follows:
private void ProjGroupLookup(FormStringControl _control)
{
    msCtrlProjGroups = SysLookupMultiSelectGrid::construct(_control, _control);
    msCtrlProjGroups.parmQuery(this.ProjGroupQuery());
    msCtrlProjGroups.run();
}
The following method returns the query for ProjGroupLookup to fill in the data.
private Query ProjGroupQuery()
{
    Query       query;
    query = new query();
    query.addDataSource(tableNum(ProjGroup));
    query.dataSourceTable(tableNum(ProjGroup)).addSelectionField(fieldNum(ProjGroup, ProjGroupId));
    query.dataSourceTable(tableNum(ProjGroup)).addSelectionField(fieldNum(ProjGroup, Name));
    return query;
}
Implementation of Project names lookup:
private void ProjNamesLookup(FormStringControl _control)
{
    msCtrlProjNames = SysLookupMultiSelectGrid::construct(_control, _control);
    msCtrlProjNames.parmQuery(this.ProjNameQuery());
    msCtrlProjNames.run();
}
The following method returns the query for ProjNamesLookup to fill in the data; the project group range is also applied to the query that is selected on the parameter screen.
private Query ProjNameQuery()
{
    Query            query;
    int              counter;
    query = new query();
    query.addDataSource(tableNum(ProjTable));
    if(msCtrlProjGroups){
        //container is filled with selected project groups on the parameter screen
        ProjGroupsContainer = msCtrlProjGroups.getSelected();
    }
    //Loop over the container values and apply range to query
    for(counter = 1; counter <= conLen(ProjGroupsContainer); counter++)
    {
query.dataSourceTable(tableNum(ProjTable)).addRange(fieldNum(ProjTable,     ProjGroupId)).value(queryValue(ProjGroup::sl_findRecId(conPeek(ProjGroupsContainer , counter)).ProjGroupId));
    }
    query.dataSourceTable(tableNum(ProjTable)).addSelectionField(fieldNum(ProjTable, ProjId));
    query.dataSourceTable(tableNum(ProjTable)).addSelectionField(fieldNum(ProjTable, Name));
    return query;
}
Implementation of Customer names lookup:
private void CustNamesLookup(FormStringControl _control)
{
    msCtrlCustNames = SysLookupMultiSelectGrid::construct(_control, _control);
    msCtrlCustNames.parmQuery(this.CustNameQuery());
    msCtrlCustNames.run();
}
The following method returns the query for CustNamesLookup to fill in the data; only those customers are filled whose projects are selected in project names parameter.
private Query CustNameQuery()
{
    Query  query;
    int    counter;
    query = new query();
    query.addDataSource(tableNum(CustTable));
    query.dataSourceTable(tablenum(CustTable)).addDataSource(tableNum(DirPartyTable));
    if(msCtrlProjNames)
    {
        //container is filled with selected projects on the parameter screen
        ProjIdContainer = msCtrlProjNames.getSelected();
    }
    //Loop over the container values and apply range to query
    for(counter = 1; counter <= conLen(ProjIdContainer); counter++)
    {
        query.dataSourceTable(tableNum(CustTable)).addRange(fieldNum(CustTable, AccountNum)).
        value(queryValue(ProjTable::findRecId(conPeek(ProjIdContainer, counter)).CustAccount));
    }
    query.dataSourceTable(tableNum(CustTable)).addSelectionField(fieldNum(CustTable, AccountNum));
    //Below relation is applied to get customer name along with customer account
    query.dataSourceTable(tablenum(DirPartyTable)).joinMode(JoinMode::InnerJoin);
    query.dataSourceTable(tablenum(DirPartyTable)).relations(true);
    query.dataSourceTable(tablenum(DirPartyTable)).addSelectionField(fieldNum(DirPartyTable,  Name));
    return query;
}
This completes my implementation of multiselect lookups for SSRS report, remember to comment the super in postRun() method after overriding it, to avoid the exception of RegisterOverrideMethod was called twice for the same object for method ‘lookup’
2.       Contract class
The implementation of contract class for sl_InvoiceDetailsUIBuilder is given below:
Class Declaration:
[
    DataContractAttribute,
    SysOperationContractProcessingAttribute(classstr(SL_InvoiceDetailsUIBuilder)),
    SysOperationGroupAttribute('Date range', literalStr("@SYS329083"),  '1',FormArrangeMethod::HorizontalFlushRight),
    SysOperationGroupAttribute('Criteria', literalStr("Criteria"),'2')
]
class SL_InvoiceDetailsContract
{
    FromDate    fromDate;
    ToDate      toDate;
    List        projGroup, projName, Customers;
}
From Date data contract methods:
[
    DataMemberAttribute('FromDate'),
    SysOperationLabelAttribute(literalStr("@SYS329084")),
    SysOperationGroupMemberAttribute('Date range'),
    SysOperationDisplayOrderAttribute('1')
]
public FromDate parmFromDate(FromDate _fromDate = fromDate)
{
    fromDate = _fromDate;
    return fromDate;
}
To Date data contract methods:
[
    DataMemberAttribute('ToDate'),
    SysOperationLabelAttribute(literalStr("@SYS329086")),
    SysOperationGroupMemberAttribute('Date range'),
    SysOperationDisplayOrderAttribute('2')
]
public ToDate parmToDate(ToDate _toDate = toDate)
{
    toDate = _toDate;
    return toDate;
}
Project Group data contract methods:
[
    DataMemberAttribute("ProjGroupList"),
    AifCollectionTypeAttribute("ProjGroupList", Types::String),
    SysOperationLabelAttribute(literalStr("Project Groups")),
    SysOperationGroupMemberAttribute('Criteria'),
    SysOperationDisplayOrderAttribute('1')
]
public List parmProjGroups(List _projGroups = projGroup)
{
    projGroup = _projGroups;
    return projGroup;
}
Project Names data contract methods:
[
    DataMemberAttribute("ProjNameList"),
    AifCollectionTypeAttribute("ProjNameList", Types::String),
    SysOperationLabelAttribute(literalStr("Project Names")),
    SysOperationGroupMemberAttribute('Criteria'),
    SysOperationDisplayOrderAttribute('2')
]
public List parmProjNames(List _projNames = projName)
{
    projName = _projNames;
    return projName;
}
Customer Names data contract methods:
[
    DataMemberAttribute("CustNameList"),
    AifCollectionTypeAttribute("CustNameList", Types::String),
    SysOperationLabelAttribute(literalStr("Customers")),
    SysOperationGroupMemberAttribute('Criteria'),
    SysOperationDisplayOrderAttribute('3')
]
public List parmCustNames(List _custNames = Customers)
{
    Customers = _custNames;
    return Customers;
}
This completes my data contract class implementation, Below are the few snapshots for demonstration.  
3.       Demonstration
Figure 1 : Multi select Project group parameter
Figure 2: Multi select Project names parameter filtered according to project groups selected
Figure 3: Multi select customer parameter filtered according to project names
Note : This article assumes that you have prior basic knowledge of Data contract class, User Interface (UI) Builder Class and Report Data Provider Class.

AX 2012 R3 X++ code to select multiple values in the SSRS report parameters

// Step 1: Create a contract class 
[
DataContractAttribute,
SysOperationContractProcessingAttribute(classstr(AOCustParametersUIBuilder))
]
class RBCustDataContract implements SysOperationValidatable
{

    List             custAccountList;

}

// Step 2 : Create a parm method.
[
DataMemberAttribute(identifierStr(CustomerAccountList)),
AifCollectionTypeAttribute("@SYS14787", Types::String),
SysOperationLabelAttribute(literalStr("@SYS14787")),
SysOperationHelpTextAttribute(literalStr("@SYS14787")),
SysOperationDisplayOrderAttribute('1')
]
public List parmCustAccountList(List _custAccountList = custAccountList)
{
    custAccountList = _custAccountList;
    return custAccountList;
}

// Step 3: Create a UI Builder Class:
class AOCustParametersUIBuilder extends SysOperationAutomaticUIBuilder
{
    DialogField     dialogCust;
}

// Step 4 : Create a new build method.

public void build()
{
    RBCustDataContract       contract;

    contract = this.dataContractObject() as RBCustDataContract ;

    dialogCust   =   this.addDialogField(methodStr(RBCustDataContract , parmCustAccountList), contract);
 
}

// Step 5: Create a new lookup method for customer

private void custTableLookup(FormStringControl _control)
{
    Query       query;
    container   conCustTable;

    query = new Query(queryStr(CustTableSRS));

    SysLookupMultiSelectGrid::lookup(
    query,
    _control,
    _control,
    conCustTable);
}

// Step 6 : Create post build method.

public void postBuild()
{
    RBCustDataContract       contract;

    super();

    contract = this.dataContractObject() as RBCustDataContract       ;

    // multiselect lookup for Customer account
    dialogCust = this.bindInfo().getDialogField(contract,methodStr(RBCustDataContract       , parmCustAccountList));

    dialogCust.registerOverrideMethod(methodStr(FormStringControl, lookup),methodStr(AOCustParametersUIBuilder , custTableLookup),this);
    if (dialogCust)
    {
        dialogCust.lookupButton(2);
    }
}

//Step 7:  Create postRun method if you need

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


// Step 8 :Create a Data Provider Class 

[
SRSReportParameterAttribute(classstr(RBCustDataContract ))
]
class RBCustDP extends  SRSReportDataProviderBase
{
    CustLedgerTmp _custLedgerTmp;  // declare the temporary table
}

//Step 9 :  Create a method to get the temporary table.

[SRSReportDataSetAttribute(tableStr(CustLedgerTmp ))]
public CustLedgerTmp getCustLedgerTmp ()
{
    select * from _custLedgerTmp;
        return _custLedgerTmp;
}

//Step 10 : Create a processReport method.

[SysEntryPointAttribute]
public void processReport()
{
     ListIterator                        custAccountListIterator;
     RBCustDataContract        dataContract;


   dataContract = this.parmDataContract();
   custAccountListIterator     = new ListIterator(dataContract.parmCustAccountList());

    // get the multi select value using ListIterator and apply your logic
    while(custAccountListIterator.more())
    {
        info(strfmt("%1",custAccountListIterator.value()));
        custAccountListIterator.next();
    }
}








AX 2012 R3 Invent Marking through X++ code

static void RB_MarkInventTrans(InventTransId _inventTransId,InventTransId _refInventTransId,InventQty _qtyTomark)
{
    InventTrans issueInventTrans;
    TmpInventTransMark tmpInventTransMask;
    Map mapMarkNow;
    container con;
    real qty;
    Map mapTmp;
    MapEnumerator mapEnumerator;

    InventTransOriginId issueInventTransOriginId =
        InventTransOrigin::findByInventTransId(_inventTransId).RecId;

    InventTransOriginId receiptInventTransOriginId =
        InventTransOrigin::findByInventTransId(_refInventTransId).RecId;

    InventQty qtyToMark = _qtyTomark;

    ttsBegin;

    issueInventTrans = InventTrans::findByInventTransOrigin(
        issueInventTransOriginId);

    [con, qty] = TmpInventTransMark::packTmpMark(
        InventTransOrigin::find(issueInventTransOriginId),
        issueInventTrans.inventDim(),
        issueInventTrans.Qty);

    mapTmp = Map::create(con);
    mapEnumerator = mapTmp.getEnumerator();
    while (mapEnumerator.moveNext())
    {
        tmpInventTransMask = mapEnumerator.currentValue();

        if (tmpInventTransMask.InventTransOrigin == receiptInventTransOriginId)
        {
            tmpInventTransMask.QtyMarkNow = qtyToMark;
            tmpInventTransMask.QtyRemain -= tmpInventTransMask.QtyMarkNow;
            mapMarkNow = new Map(Types::Int64, Types::Record);
            mapMarkNow.insert(tmpInventTransMask.RecId, tmpInventTransMask);

            TmpInventTransMark::updateTmpMark(
                issueInventTransOriginId,
                issueInventTrans.inventDim(),
                -qtyToMark,
                mapMarkNow.pack());
        }
    }

    ttsCommit;
}

Install and Configure Zpl Printer on D365 F&O

  Setup Zpl Printer On D365 F&O Posted on Recently, I have had an opportunity review the possibilities to print license plates within D3...