Thursday, July 29, 2021

Get current user store in d365fo using X++.

 Try this below code.


    DirAddressBookParty dirAddParty; RetailStoreAddressBook retailStoreaddBook; RetailStoreTable retailStoreTable; ; select firstonly dirAddParty join retailStoreaddBook where retailStoreaddBook.AddressBook == dirAddParty.AddressBook && dirAddParty.Party == HcmWorker::findByPerson(DirPersonuser::find(curUserId()).PersonParty).Person && retailStoreaddBook.AddressBookType == RetailAddressBookType::Employee join retailStoreTable where retailStoreTable.RecId == retailStoreaddBook.StoreRecId;


Keep Daxing!!

Thursday, July 15, 2021

Get year start date and End date in D365Fo using X++

 

Note : DateEndYr(), DateStartyr() -- "IsObsolete". Instead of this functions replace with below function.


    PeriodStart start; PeriodEnd End; xSession xSession = new xSession(); start = DateTimeUtil::getStartOfYearDate(xSession.preferredLocale(), DateTimeUtil::getToday(DateTimeUtil::getUserPreferredTimeZone())); End = DateTimeUtil::getEndOfYearDate(xSession.preferredLocale(), DateTimeUtil::getToday(DateTimeUtil::getUserPreferredTimeZone()));// today()); info(strFmt('start date%1,endDate%2',start,End));


Keep Daxing!!


Wednesday, July 14, 2021

Capturing infolog messages in D365FO using X++.

    Capturing info log messages in D365FO. We can get it in multiple ways.

    
  • Way 1.      
public static str getError()
{
    SysInfologEnumerator    sysInfologEnumerator;
    SysInfologMessageStruct infoMessageStruct;
    str                     logMessage;
    str                           logString;
    str                          ret;
    int                          i;
    #Define.NewLine('\n')

    sysInfologEnumerator = SysInfologEnumerator::newData(infolog.infologData());

    while (sysInfologEnumerator.moveNext())
    {
	i = 1;

	if (logMessage)
	{
	    logMessage += #Newline;
	}

	infoMessageStruct = SysInfologMessageStruct::construct(sysInfologEnumerator.currentMessage());

	while (i <= infoMessageStruct.prefixDepth())
	{
	    logString = logString + infoMessageStruct.preFixTextElement(i) + '. ';
	    i++;
	}

	logString = logString + infoMessageStruct.message();
	logMessage = logMessage + infoMessageStruct.message();
    }

    return logMessage;
}
      
  • Way 2
public void method()
{
    System.Exception        ex;
	
    try
    {
	
    }         
    catch
    {
        ex = CLRInterop::getLastException().GetBaseException();
	error(ex.get_Message());

        --- or----

        System.Exception e = ex;
	while (e != null)
	{
	    errorMessage += e.Message;
	    e = e.InnerException;
	}
    }
}


  • Way 3  (Get the type of exception using the below code.)
    container infologContents = infolog.cut(); 

    for (int i = 1; i <= conLen(infologContents); i++)
    {
	container infologLine = conPeek(infologContents, i);

	Exception errorLevel = conPeek(infologLine, 1);
	str logMessage = conPeek(infologLine, 2);
				
	if (logMessage)
	{
	    switch (errorLevel)
	    {
		case Exception::Error :
		    errors.add(logMessage);
		    break;

		case Exception::Warning :
		    warnings.add(logMessage);
		    break;

		case Exception::Info :
		    infos.add(logMessage);
		    break;

		default:
		    Debug::assert(false);
		    warnings.add(logMessage);
		    break;
	    }
        }
    }

  • Way 4
SysInfologEnumerator 	enumerator;
SysInfologMessageStruct msgStruct;
Exception 		exception;
str 			error;

enumerator = SysInfologEnumerator::newData(infolog.cut());

while (enumerator.moveNext())
{
    msgStruct = new SysInfologMessageStruct(enumerator.currentMessage());
    exception = enumerator.currentException();
    error = strfmt("%1 %2", error, msgStruct.message()) + "\n";
}

  • Way 5 (Return only error messages from info log)
    SysInfologEnumerator sysInfologEnumerator = SysInfologEnumerator::newData(infolog.infologData());
    while (sysInfologEnumerator.moveNext())     { switch (sysInfologEnumerator.currentException()) {     case Exception::Error:     retvalue = strFmt("%1", sysInfologEnumerator.currentMessage());     break; }     }

  • Way 6
    infolog.text(infologLine());   
  • Way 7
 	str errormessage;
	errormessage = infolog.text(infologLine());
	errormessage = infolog.text(infologLine()-1);
	errormessage = errormessage + " "+ infolog.text(infologLine());
	Error(errormessage);
    

Keep daxing!!

QueryBuildFieldList in SSRS Dp class in D365FO.

For improving performanance of report we are using QueryBuildFieldList.        
        Query query; QueryBuildDataSource qbds; str testsalesman, teststore; List storeList = new List(Types::String), salesmanList = new List(Types::String); QueryBuildFieldList fldList_RetailTransactionSalesTrans; Map fieldMapping; ; contract = this.parmDataContract() as BranchAndSalesmanInvoiceContract;// contract class fromDate = contract.parmFromDate(); toDate = contract.parmToDate(); salesmanList = contract.parmSalesmanId(); storeList = contract.parmstoreId(); testsalesman = salesmanList.toString(); teststore = storeList.toString(); teststore = strRem(teststore,"<"); teststore = strRem(teststore,">"); query = new Query(); qbds = query.addDataSource(tableNum(BranchAndSalesmanInvoiceStagging)); // Main table. if(salesmanList) { qbds.addRange(fieldNum(BranchAndSalesmanInvoiceStagging, Salesman)).value(testsalesman); } if(storeList) { qbds.addRange(fieldNum(BranchAndSalesmanInvoiceStagging, Store)).value(teststore); } qbds.addGroupByField(fieldNum(BranchAndSalesmanInvoiceStagging, Store)); qbds.addGroupByField(fieldNum(BranchAndSalesmanInvoiceStagging, Salesman)); qbds.addGroupByField(fieldNum(BranchAndSalesmanInvoiceStagging, ReceiptId)); ttsbegin; delete_from branchAndSalesmanInvoiceTmp;// temp table buffer. ttscommit; qbds.fields().clearFieldList(); fldList_RetailTransactionSalesTrans = qbds.fields(); fldList_RetailTransactionSalesTrans.addField(fieldNum(BranchAndSalesmanInvoiceStagging, Salesman)); fldList_RetailTransactionSalesTrans.addField(fieldNum(BranchAndSalesmanInvoiceStagging, Store)); fldList_RetailTransactionSalesTrans.addField(fieldNum(BranchAndSalesmanInvoiceStagging, ReceiptId)); fldList_RetailTransactionSalesTrans.dynamic(QueryFieldListDynamic::No); fieldMapping = new Map(Types::String, Types::Container);// BranchAndSalesmanInvoiceTmp - Main temp table. fieldMapping.insert(fieldStr(BranchAndSalesmanInvoiceTmp, EmpId), [qbds.uniqueId(), fieldStr(BranchAndSalesmanInvoiceStagging, Salesman)]); fieldMapping.insert(fieldStr(BranchAndSalesmanInvoiceTmp, Store), [qbds.uniqueId(), fieldStr(BranchAndSalesmanInvoiceStagging, store)]); fieldMapping.insert(fieldStr(BranchAndSalesmanInvoiceTmp, ReceiptId), [qbds.uniqueId(), fieldStr(BranchAndSalesmanInvoiceStagging, ReceiptId)]); query::insert_recordset(branchAndSalesmanInvoiceTmp, fieldMapping, query);// Inserting data into temp table.
Keep daxing!!

Add a new field in standard report in D365 FO/ SSRS.

  • Create an extension of the SalesInvoiceHeaderFooterTmp table and add the fields.

  • Copy the post-handler event method of processReport() of the DP class.

  • Write the following logic to insert the data into the field:
class SalesInvoiceDPEventHandler
{
    [PostHandlerFor(classStr(SalesInvoiceDP), methodStr(SalesInvoiceDP, processReport))]
    public static void SalesInvoiceDP_Post_processReport(XppPrePostArgs args)
    {
        SalesInvoiceDP                  dpInstance = args.getThis() as SalesInvoiceDP;
        SalesInvoiceHeaderFooterTmp     tmpTable   = dpInstance.getSalesInvoiceHeaderFooterTmp();
        FormLetterRemarks               formLetterRemarks;
        CustPackingSlipJour             custPackingSlipJour;

        ttsbegin;
        while select forUpdate tmpTable
        {
            select firstonly firstfast PackingSlipId from custPackingSlipJour
                where custPackingSlipJour.SalesId == tmpTable.SalesId;

            tmpTable.Email          = CustTable::find(SalesTable::find(tmpTable.SalesId).CustAccount).email();
            tmpTable.DeliveryNote   = custPackingSlipJour.PackingSlipId;
            tmpTable.update();
        }
        ttscommit;
    }

}

---------------------------------OR-----------------------------------------
[ExtensionOf(classstr(SalesInvoiceDP))]
final class SalesInvoiceDP_Extension
{
    protected void populateSalesInvoiceTmp(CustInvoiceJour _custInvoiceJour,
        CustInvoiceTrans _custInvoiceTrans,
        TaxSpec _taxSpec,
        CustPaymSchedLine _custPaymSchedLine,
        CustTrans _prepaymentCustTrans,
        TaxTrans _prepaymentTaxTrans)
    {

        next populateSalesInvoiceTmp(_custInvoiceJour,
                                    _custInvoiceTrans,
                                    _taxSpec,
                                    _custPaymSchedLine,
                                    _prepaymentCustTrans,
                                    _prepaymentTaxTrans);

        salesInvoiceTmp.TrackingId = _custInvoiceTrans.salesLine().TrackingId;
    }

    protected void populateSalesInvoiceHeaderFooterTmp(CustInvoiceJour _custInvoiceJour, CompanyInfo _companyInfo)
    {
        CustPackingSlipJour             custPackingSlipJour;

        next populateSalesInvoiceHeaderFooterTmp(_custInvoiceJour, _companyInfo);

        select firstonly firstfast PackingSlipId from custPackingSlipJour
                where custPackingSlipJour.SalesId == salesInvoiceHeaderFooterTmp.SalesId;

        salesInvoiceHeaderFooterTmp.Email          = CustTable::find(_custInvoiceJour.InvoiceAccount).email();
        salesInvoiceHeaderFooterTmp.DeliveryNote   = custPackingSlipJour.PackingSlipId;
    }
}
  • You can also use the OnInserting event of the table instead of processReport() of DP class.
  •  Find out the SalesInvoicereport in the AOT
    • Right-click the report and click Duplicate in the project.
    • Restore the report data source to get additional fields.

    • Customize the design and add fields as per your requirements.
    • Create another class named SalesInvoiceControllerExt
      which extends the SalesInvoiceController class. Override the main() method. Give the new report and its design name in it.
    • Add the following logic in the SalesInvoiceControllerExt class:
class SalesInvoiceControllerExt extends SalesInvoiceController
{
    public static SalesInvoiceControllerExt construct()
    {
        return new SalesInvoiceControllerExt();
    }

    public static void main(Args _args)
    {
        
        SrsReportRunController formLetterController = SalesInvoiceControllerExt::construct();
        SalesInvoiceControllerExt controller = formLetterController;
        controller.parmArgs(_args);
        controller.parmReportName(ssrsReportStr(SalesInvoiceExt, Report));
        controller.parmShowDialog(false);
        controller.parmDialogCaption("@SYS22766");
        controller.startOperation();        
    }

}
  • Create another class named PrintMgtDocTypeHandlersExt.
  • Add a method in it that subscribes to the event delegate of the PrintMgmtDocType class.
  • Add the following logic in the PrintMgtDocTypeHandlersExt class:
class PrintMgtDocTypeHandlersExt
{
    [SubscribesTo(classstr(PrintMgmtDocType), delegatestr(PrintMgmtDocType, getDefaultReportFormatDelegate))]
    public static void getDefaultReportFormatDelegate(PrintMgmtDocumentType _docType, EventHandlerResult _result)
    {
        switch (_docType)
        {
            case PrintMgmtDocumentType::SalesOrderInvoice:
                _result.result(ssrsReportStr(SalesInvoiceExt, Report));
                break;
        }
    }
}

  • Create an extension of the following menu items which executes the report:
          • SalesInvoiceOriginal
          • SalesInvoiceCopy
  • Change the controller class name in extended menu items.
  • Save, build, synchronize and deploy.

Output:



If the system is called Standard design. Please follow the below steps.
  • AR-> Setup-> Forms ->Form setup -> Genral tab -> print managment(button). 
  • Right click on Customer invoice  and select New.
  • In Report format select our custom design.

Keep daxing!!

Monday, July 12, 2021

DB restore in AX(.bak file).

Follow the below steps.

1.Stop the Ax services.

  1. MS Batch
  2. MS Data import.
  3. World wide.
  4. Management reporter.

2. Close the Visual studio. 

3. Open SSMS with the admin.

4. Right-click on databases and select Restore Database.


5. Select Device and select the path of the file and assign a name to the Database.


6. Click on add and select file.


7. Remove check of tail-log back up and check the close existing connections.


8.Start the services, open VS, and set full sync.


For the .bacpac file Please Click here.

Keep Daxing!!

Change Data base name in SQL through query.



USE master

GO


ALTER DATABASE AXDB

SET SINGLE_USER

WITH ROLLBACK IMMEDIATE

GO


EXEC master..sp_renamedb 'AXDB','AXDB_Old'

GO


ALTER DATABASE AXDB_Old

SET MULTI_USER

GO


Keep daxing!!

Get Main Account from Ledger Dimension in D365FO using X++



 //Get MainAccountId from LedgerDimension
            LedgerDimensionFacade::getMainAccountFromLedgerDimension(LedgerDimension).MainAccountId;
or      
    MainAccount::findByLedgerDimension(ledgerDimension).MainAccountId;

     //Get Name of MainAccountId from LedgerDimension
        LedgerDimensionFacade::getMainAccountFromLedgerDimension(LedgerDimension).Name;

Keep Daxing!!


Creating and posting a free text invoice using X++ in D365Fo



        ttsBegin;

        // Create header

        custInvoiceTable.clear();

        custInvoiceTable.initValue();

        custInvoiceTable.OrderAccount = "US-001";

        custInvoiceTable.modifiedField(fieldNum(CustInvoiceTable, OrderAccount));

        custInvoiceTable.insert();

        // Create line

        custInvoiceLine.clear();

        custInvoiceLine.initValue();

        custInvoiceLine.ParentRecId = custInvoiceTable.RecId;

        custInvoiceLine.initFromCustInvoiceTable(custInvoiceTable);

        custInvoiceLine.Description = "Free text invoice";

        custInvoiceLine.Quantity = 2;

        custInvoiceLine.modifiedField(fieldNum(CustInvoiceLine, Quantity));

        custInvoiceLine.UnitPrice = 100;

        custInvoiceLine.modifiedField(fieldNum(CustInvoiceLine, UnitPrice));

        //Get MainAccountId from LedgerDimension

                    LedgerDimensionFacade::getMainAccountFromLedgerDimension(LedgerDimension).MainAccountId;

        //Get Name of MainAccountId from LedgerDimension

        LedgerDimensionFacade::getMainAccountFromLedgerDimension(LedgerDimension).Name;

        ledgerDimensionAccount = DimensionDefaultingService::serviceCreateLedgerDimension(

            DimensionStorage::getDefaultAccountForMainAccountNum("110110"), dimensionDefault);

        custInvoiceLine.LineNum         = CustInvoiceLine::lastLineNum_W(custInvoiceLine.ParentRecId) + 1;

        custInvoiceLine.LedgerDimension = ledgerDimensionAccount;

        custInvoiceLine.modifiedField(fieldNum(CustInvoiceLine, LedgerDimension));

        custInvoiceLine.insert();


        // Post

        custPostInvoice = new CustPostInvoice(custInvoiceTable);

        custPostInvoice.run();

        ttsCommit;

    }

    catch

    {

        throw error(error::wrongUseOfFunction(funcName()));

    }


Keep Daxing!!