Tuesday, December 27, 2022

Posting Invoice/Product Receipt/Packing Slip - D365FO X++

Posting Vendor invoice based on Product receipt

public void postPurchaseInvoiceJournal()

    {

        VendPackingSlipJour             vendPackingSlipJour;

        VendPackingSlipTrans            vendPackingSlipTrans;

        TmpFrmVirtual                   tmpFrmVirtual;

        boolean                         isValidToProcess = false;

        container                       conTmpFrmVirtual;

        SysQueryRun                     chooseLinesQuery;

        SysQueryRun                     chooseLinesPendingInvoiceQuery;


        select firstonly vendPackingSlipJour

            order by RecId desc

            where vendPackingSlipJour.PackingSlipId == shipmentId;


        if(vendPackingSlipJour)

        {

            isValidToProcess = true;

        }


        chooseLinesQuery = new SysQueryRun(queryStr(PurchUpdate));

       

        List packingSlipList = new List(Types::Record);

        while select OrigPurchId from vendPackingSlipTrans

            group by OrigPurchId

            where vendPackingSlipTrans.PackingSlipId == vendPackingSlipJour.PackingSlipId

        {

            tmpFrmVirtual.clear();

            tmpFrmVirtual.TableNum      = tableNum(VendPackingSlipJour);

            tmpFrmVirtual.RecordNo      = vendPackingSlipJour.RecId;

            tmpFrmVirtual.NoYes         = NoYes::Yes;

            tmpFrmVirtual.Id            = vendPackingSlipTrans.OrigPurchId;

            tmpFrmVirtual.insert();


            packingSlipList.addEnd(tmpFrmVirtual);

            conTmpFrmVirtual            = packingSlipList.pack();


            chooseLinesQuery.query().dataSourceTable(tableNum(PurchTable)).addRange(fieldNum(PurchTable, PurchId)).value(queryValue(vendPackingSlipTrans.OrigPurchid));

        }


        chooseLinesQuery.query().interactive (false);

        chooseLinesQuery.saveUserSetup (false);

        chooseLinesQuery.query().addDataSource(tableNum(VendInvoiceInfoTable)).enabled(false);


        chooseLinesPendingInvoiceQuery = new SysQueryRun(queryStr(PurchUpdatePendingInvoice));

        chooseLinesPendingInvoiceQuery.query().dataSourceTable(tableNum(PurchTable)).addRange(fieldNum(PurchTable,PurchId)).value(queryValue(''));


        TransDate postingDate = getTodayDate;


        PurchFormLetter_Invoice purchFormLetter;

        purchFormLetter = PurchFormLetter::construct(DocumentStatus::Invoice);

        purchFormLetter.chooseLinesQuery (chooseLinesQuery);

        purchFormLetter.parmQueryChooseLinesPendingInvoice(chooseLinesPendingInvoiceQuery);

        purchFormLetter.transDate (postingDate);

        purchFormLetter.parmParmTableNum(shipmentId);

        purchFormLetter.printFormLetter (NoYes::No);

        purchFormLetter.sumBy (AccountOrder::Account);

        purchFormLetter.specQty (PurchUpdate::PackingSlip);

        purchFormLetter.selectFromJournal(conTmpFrmVirtual);

        purchFormLetter.reArrangeNow(true);         

        purchFormLetter.runOperation();


        if(purchFormLetter.parmJournalRecord())

        {            

            VendInvoiceJour                 invoiceJour;

            

            invoiceJour = VendInvoiceJour::findRecId(purchFormLetter.parmJournalRecord().RecId);

            if(invoiceJour)

            {

//Successful posting

            }

        }

    }


Process Customer invoice based on PackingSlip

--> Normal Sales order/ Direct delivery sales order

public void processSalesInvoiceDataToPost(str  _salesPackingSlipId)

    {

        salesFormletterParmData     salesFormLetterParmData;

        SalesParmUpdate             salesParmUpdate;

        SalesTable                  salesTable;

        SalesParmTable              salesParmTable;

        CustPackingSlipJour         custPackingSlipJour;

        CustPackingSlipTrans        custPackingSliptrans;

        SalesLine                   salesLine;


        TransDate postingDate = getToday;


        select firstonly custPackingSlipJour

            where custPackingSlipJour.PackingSlipId == _salesPackingSlipId;


        salesFormLetterParmData = salesFormletterParmData::newData(DocumentStatus::Invoice, VersioningUpdateType::Initial);

       

        salesFormLetterParmData.parmOnlyCreateParmUpdate(true);

        salesFormLetterParmData.parmProforma(this.parmIsProformaProcess());

        salesFormLetterParmData.createData(false);

        salesParmUpdate = salesFormLetterParmData.parmParmUpdate();


        InventTransOrigin       inventTransOrigin;

        InventTrans             inventTrans;


        if(_salesPackingSlipId)

        {

            salesTable  = salesTable::find(custPackingSlipJour.SalesId);

            salesParmTable.clear();

            salesParmTable.TransDate                = transportInvoiceTable.InvoiceDate;

            salesParmTable.Ordering                 = DocumentStatus::Invoice;

            salesParmTable.ParmJobStatus            = ParmJobStatus::Waiting;

            salesParmTable.salesId                  = salesTable.salesId;

            salesParmTable.salesName                = salesTable.salesName;

            salesParmTable.DeliveryName             = salesTable.DeliveryName;

            salesParmTable.DeliveryPostalAddress    = salesTable.DeliveryPostalAddress;

            salesParmTable.CustAccount              = salesTable.CustAccount;

            salesParmTable.CurrencyCode             = salesTable.CurrencyCode;

            salesParmTable.InvoiceAccount           = salesTable.InvoiceAccount;

            salesParmTable.ParmId                   = salesParmUpdate.ParmId;

            salesParmTable.insert();

       

            while select custPackingSliptrans group by OrigSalesId

                where custPackingSliptrans.PackingSlipId == custPackingSlipJour.PackingSlipId

                    && custPackingSliptrans.OrigSalesId != custPackingSlipJour.SalesId

            {

                this.processSalesParmSubTableData(salesParmTable, SalesTable::find(custPackingSliptrans.OrigSalesId));

            }

       

            custPackingSliptrans.clear();

            while select custPackingSliptrans

                where custPackingSliptrans.PackingSlipId == custPackingSlipJour.PackingSlipId

                    join salesLine

                        where salesLine.InventTransId == custPackingSliptrans.InventTransId

            {

                this.processSalesParmLinesTableData(salesParmTable, salesLine, custPackingSliptrans);

            }

        }

        else 

        {

            //Update reference on salesParmUpdate

            if(salesParmUpdate)

            {

                ttsbegin;

                salesParmUpdate.selectForUpdate(true);

                salesParmUpdate.SpecQty        = SalesUpdate::PickingList;

                salesParmUpdate.update();

                ttscommit;

            }

        SalesFormLetter_Invoice salesFormLetter = salesFormLetter::construct(DocumentStatus::Invoice);

        salesFormLetter.transDate(postingDate);

        salesFormLetter.proforma(this.parmIsProformaProcess()); 

         salesFormLetter.specQty(salesUpdate::PackingSlip); 

        salesFormLetter.salesTable(salesTable);

        salesFormLetter.parmId(salesParmTable.ParmId);

        salesFormLetter.salesParmUpdate(salesFormLetterParmData.parmParmUpdate());

        if(//Need print destination setting)

        {

            SRSPrintDestinationSettings     printSettings = new SRSPrintDestinationSettings();

            PrintSetupOriginalCopy          printSetupOriginalCopy;


            printSetupOriginalCopy = this.parmIsProformaProcess() ? PrintSetupOriginalCopy::Copy : PrintSetupOriginalCopy::Original;

            printSettings = new SRSPrintDestinationSettings(salesFormLetter.printerSettingsFormletter(printSetupOriginalCopy));

            printSettings.printMediumType(PrintMediumType::Printer);

            //printSettings.DestinationSettings(printSettings);

            salesFormLetter.updatePrinterSettingsFormLetter(printSettings.pack());

        }

//To open FORM, User will click post

        salesFormLetter.startOperation();// process operation to post invoice

//To Direct POST without UI FORM open

        salesFormLetter.runOperation();// process operation to post invoice


        if (salesFormLetter.parmJournalRecord().RecId )

        {

// Success posting

        }

    }


    /// <summary>

    /// Process sales update parm history sub table data for posting invoice

    /// </summary>

    /// <param name = "_salesParmTable">current salesParmTable</param>

    /// <param name = "_SalesTable">current sales id to process</param>

    public void processSalesParmSubTableData(SalesParmTable     _salesParmTable, SalesTable     _SalesTable)

    {

        SalesParmSubTable       parmSubTable;


        parmSubTable.clear();

        parmSubTable.initValue();

        parmSubTable.InitFromSalesParmTable(_salesParmTable);

        parmSubTable.initFromSalesTable(_SalesTable);

        parmSubTable.insert();

    }


    /// <summary>

    /// Process sales update parm history sub line table data for posting invoice

    /// </summary>

    /// <param name = "_salesParmTable">current salesParmTable</param>

    /// <param name = "_salesLine">current salesLine</param>

    /// <param name = "_custPackingSliptrans">current custPackingslipTrans</param>

    /// <param name = "_qty">current trasnprot line qty</param>

    public void processSalesParmLinesTableData(SalesParmTable       _salesParmTable, SalesLine      _salesLine, CustPackingSlipTrans    _custPackingSliptrans, Qty      _qty = 0)

    {

        SalesParmLine       salesParmLine;

        SalesParmSubLine    salesParmSubLine;


        salesParmLine.clear();

        salesParmLine.initValue();

        salesParmLine.InitFromsalesLine(_salesLine);

        salesParmLine.DeliverNow    = _qty ? _qty : _custPackingSliptrans.Qty;  

        salesParmLine.ParmId        = _salesParmTable.ParmId;

        salesParmLine.TableRefId    = _salesParmTable.TableRefId;

        salesParmLine.setQty(DocumentStatus::Invoice, false, true);

        salesParmLine.setLineAmount(_salesLine);

        salesParmLine.insert();


        salesParmSubLine.clear();

        salesParmSubLine.initValue();

        salesParmSubLine.initFromCustPackingSlipTrans(_custPackingSliptrans);

        salesParmSubLine.initFromSalesParmLine(salesParmLine);

        if(_custPackingSliptrans    == null) 

        {

            salesParmSubLine.InventNow              = _qty;

            salesParmSubLine.DeliverNow             = _qty;

        }

        salesParmSubLine.insert();

    }


    public void processMultipleSOInvoice()

    {

        SalesFormLetter_invoice salesFormLetter;

        CustPackingSlipJour custPackingSlipJour;

        TmpFrmVirtual tmpFrmVirtual;

        salesFormletterParmData     salesFormLetterParmData;

        SalesParmLine   salesParmLine;

        SalesParmUpdate             salesParmUpdate;

        List selectedList = new List(Types::Record);


        tmpFrmVirtual.setTmp();     

        while select from custPackingSlipJour

            where custPackingSlipJour.ReferenceId== 'ReferenceId' //Reference Id custom field

        {          


            tmpFrmVirtual.clear();

            tmpFrmVirtual.TableNum = custPackingSlipJour.TableId;

            tmpFrmVirtual.RecordNo = custPackingSlipJour.RecId;

            tmpFrmVirtual.NoYes = NoYes::Yes;

            tmpFrmVirtual.Id = custPackingSlipJour.SalesId;

            tmpFrmVirtual.insert();

            if (!salesParmUpdate)

            {

                salesFormLetterParmData = salesFormletterParmData::newData(DocumentStatus::Invoice, VersioningUpdateType::Initial);

       

                salesFormLetterParmData.parmOnlyCreateParmUpdate(true);

                salesFormLetterParmData.parmProforma(this.parmIsProformaProcess());//Added code bug fix 410277

                salesFormLetterParmData.createData(false);

                salesParmUpdate = salesFormLetterParmData.parmParmUpdate();

            }

            this.processMultipleSalesInvoiceParmData(custPackingSlipJour,salesParmUpdate);

        }


        while select tmpFrmVirtual

        {

            selectedList.addEnd(tmpFrmVirtual);

        }


     

        // Construct form letter

        salesFormLetter = salesFormLetter::construct(DocumentStatus::Invoice);

        // Add the packing slips to the sales form letter

        salesFormLetter.selectFromJournal(selectedList.pack());

        select firstonly salesParmLine

               where salesParmLine.ParmId == salesParmUpdate.ParmId;

       

        if(salesParmLine)

       

        {

            salesFormLetter.salesParmUpdate(salesParmUpdate);

        }

        // Reorganize as desired

        salesFormLetter.specQty(SalesUpdate::PackingSlip);

        salesFormLetter.sumBy(AccountOrder::Auto);

        salesFormLetter.transDate(transportInvoiceTable.InvoiceDate);

   


        salesFormLetter.reArrangeNow(true);

        salesFormLetter.parmId(salesParmUpdate.ParmId);

        salesFormLetter.startOperation();

     

    }


    public void processMultipleSalesInvoiceParmData(CustPackingSlipJour _custPackingSlipJour,

                                            SalesParmUpdate     _salesParmUpdate)

    {

        SalesParmUpdate             salesParmUpdate = _salesParmUpdate;

        SalesTable                  salesTable;

        SalesParmTable              salesParmTable;

        CustPackingSlipJour         custPackingSlipJour = _custPackingSlipJour;

        CustPackingSlipTrans        custPackingSliptrans;

        SalesLine                   salesLine;


        TransDate postingDate = getToday;


        if(_custPackingSlipJour.PackingSlipId)

        {

            salesTable  = salesTable::find(custPackingSlipJour.SalesId);

            salesParmTable.clear();

            salesParmTable.TransDate                = transportInvoiceTable.InvoiceDate;

            salesParmTable.Ordering                 = DocumentStatus::Invoice;

            salesParmTable.ParmJobStatus            = ParmJobStatus::Waiting;

            salesParmTable.salesId                  = salesTable.salesId;

            salesParmTable.salesName                = salesTable.salesName;

            salesParmTable.DeliveryName             = salesTable.DeliveryName;

            salesParmTable.DeliveryPostalAddress    = salesTable.DeliveryPostalAddress;

            salesParmTable.CustAccount              = salesTable.CustAccount;

            salesParmTable.CurrencyCode             = salesTable.CurrencyCode;

            salesParmTable.InvoiceAccount           = salesTable.InvoiceAccount;

            salesParmTable.ParmId                   = salesParmUpdate.ParmId;

            salesParmTable.insert();

       

            while select custPackingSliptrans group by OrigSalesId

                where custPackingSliptrans.PackingSlipId == custPackingSlipJour.PackingSlipId

                    && custPackingSliptrans.OrigSalesId != custPackingSlipJour.SalesId

            {

                this.processSalesParmSubTableData(salesParmTable, SalesTable::find(custPackingSliptrans.OrigSalesId));

            }

       

            custPackingSliptrans.clear();

            while select custPackingSliptrans

                where custPackingSliptrans.PackingSlipId == custPackingSlipJour.PackingSlipId

                    join salesLine

                        where salesLine.InventTransId == custPackingSliptrans.InventTransId

            {

                this.processSalesParmLinesTableData(salesParmTable, salesLine, custPackingSliptrans);

            }

        }

       

    }


Process Purchase product receipt - Post

public void postProductReceiptJournal()

    {

        PurchFormLetter             purchFormLetter;

        PurchFormletterParmData     purchFormLetterParmData;

        PurchParmUpdate             purchParmUpdate;

        PurchParmTable              purchParmTable;       

        SanJournalTrans   jourTrans; //Custom table

        PurchTable                  purchTable;

        PurchLine                   purchLine;

        PurchId                     purchId;

        container                   conPurchList;

        Num                         packingSlipId = purchInvoiceHeaderInbound.InvoiceId;


        purchFormLetterParmData = PurchFormletterParmData::newData(

        DocumentStatus::PackingSlip,

        VersioningUpdateType::Initial);


        select firstonly jourTrans

            where jourTrans.JournalId == this.journalId;

        purchId = jourTrans.PurchId;


        purchTable = PurchTable::find(purchId, false);

    

        purchFormLetterParmData.parmOnlyCreateParmUpdate(true);

        purchFormLetterParmData.createData(false);

        purchParmUpdate = purchFormLetterParmData.parmParmUpdate();


        // Set PurchParmTable table

        purchParmTable.clear();

        purchParmTable.TransDate                = SystemDateGet();

        purchParmTable.Ordering                 = DocumentStatus::PackingSlip;

        purchParmTable.ParmJobStatus            = ParmJobStatus::Waiting;

        purchParmTable.Num                      = packingSlipId;

        purchParmTable.PurchId                  = purchTable.PurchId;

        purchParmTable.PurchName                = purchTable.PurchName;

        purchParmTable.DeliveryName             = purchTable.DeliveryName;

        purchParmTable.DeliveryPostalAddress    = purchTable.DeliveryPostalAddress;

        purchParmTable.OrderAccount             = purchTable.OrderAccount;

        purchParmTable.CurrencyCode             = purchTable.CurrencyCode;

        purchParmTable.InvoiceAccount           = purchTable.InvoiceAccount;

        purchParmTable.ParmId                   = purchParmUpdate.ParmId;

        purchParmTable.insert();


        if(purchTable)

        {

            conPurchList += [purchTable.PurchId];

        }


        // Set PurchParmLine table

        jourTrans.clear();

        while select jourTrans

            where jourTrans.JournalId == this.journalId

                && jourTrans.purchId && jourTrans.SourceLineNumber

            join purchLine

                where purchLine.PurchId == jourTrans.purchId

                && purchLine.POL_OriginalLotID == jourTrans.SourceLineNumber

        {

            if(!conFind(conPurchList, purchTable.PurchId))

            {

                conPurchList += [jourTrans.PurchId];

                this.processPurchParmSubTable(purchParmTable,jourTrans.PurchId );

            }

            this.processPurchParmLine(purchLine, purchParmTable, jourTrans.Quantity);

        }


        purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);

        purchFormLetter.transDate(systemDateGet());

        purchFormLetter.proforma(false);

        purchFormLetter.specQty(PurchUpdate::All);

        purchFormLetter.purchTable(purchTable);

        purchFormLetter.parmParmTableNum(purchParmTable.ParmId);

        purchFormLetter.parmId(purchParmTable.ParmId);

        purchFormLetter.purchParmUpdate(purchFormLetterParmData.parmParmUpdate());

        purchFormLetter.runOperation();

        if(purchFormLetter.parmJournalRecord())

        {

            shipmentId = '';//Can get here posted number

        }

    }


    private void processPurchParmLine(PurchLine _purchLine, PurchParmTable  _purchParmTable, Qty        _curQty)

    {

        PurchParmLine               purchParmLine;


        purchParmLine.InitFromPurchLine(_purchLine);

        purchParmLine.ReceiveNow    = _curQty;

        purchParmLine.ParmId        = _purchParmTable.ParmId;

        purchParmLine.TableRefId    = _purchParmTable.TableRefId;

        purchParmLine.setQty(DocumentStatus::PackingSlip, false, true);

        purchParmLine.setLineAmount();

        purchParmLine.insert();

        this.processPurchParmSubLine(purchParmLine);

    }


    private void processPurchParmSubLine(PurchParmLine  _purchParmLine)

    {

        PurchParmSubLine               purchParmSubLine;


        purchParmSubLine.ParmId               = _purchParmLine.ParmId;

        purchParmSubLine.LineRefRecId         = _purchParmLine.RecId;

        purchParmSubLine.ReceiveNow           = _purchParmLine.ReceiveNow;

        purchParmSubLine.JournalRefRecId      = _purchParmLine.RecId;

        purchParmSubLine.JournalRefTableId    = _purchParmLine.TableId;

        purchParmSubLine.insert();

    }


    private void processPurchParmSubTable(PurchParmTable  _purchParmTable, PurchId  _origPurchId)

    {

        PurchParmSubTable       purchParmSubTable;

        PurchTable              purchTable = PurchTable::find(_origPurchId,false);


        purchParmSubTable.OrigPurchId   = _origPurchId;

        purchParmSubTable.ParmId        = _purchParmTable.ParmId;

        purchParmSubTable.TableRefId    = _purchParmTable.TableRefId;

        purchParmSubTable.PurchName     = purchTable.PurchName;

        AccountingEvent accountingEvent;

        select firstonly accountingEvent

            order by CreatedDateTime desc

            where accountingEvent.SourceDocumentHeader == purchTable.SourceDocumentHeader

                && accountingEvent.Type != AccountingEventType::PeriodClose;


        purchParmSubTable.SourceAccountingEvent   = accountingEvent.RecId;

        purchParmSubTable.insert();

    }


Process Sales packing slip - Post

In Progress

Tuesday, December 20, 2022

ADF expression - Sample & examples

ForEach loop,

@Item()

GetMetaData

@Item().Name

FileFormat -> yyMMdd_HHmmss

FormatDateTime:

@formatDateTime(utcnow(),'yyyy-MM-dd HH:mm:ss')

Date to integer to string

concat(Column_2,'_',toString(toDate(Column_3, 'MM/dd/yyyy','en-US'), 'yyyyMMdd')) 

Str upper ->  upper('test')

concat ->  concat('test-1','_','test-2')

Data Flow: SinkDataset ( enable -> optimize ->  Single partition)


If expression (Data flow)

iif(GROUPNAME == 'WG', 'Y', 'N')

Compare -> 

Ex

 iif((compare(TABLENAME,"VENDTABLE")>0),iif(isNull(sendVendorId), concat(ACCOUNTNUM,'_',PARTY,'_',PARTNERDATAAREAID),ACCOUNTNUM ),concat(ACCOUNTNUM,'_',PARTY,'_',PARTNERDATAAREAID))

iif((compare(TABLENAME,"VENDTABLE")>0),"SUPPLIER","CUSTOMER")

iif((compare(TABLENAME,"PurchLine")>0),"0",toString(round(toDecimal(EXTENDEDPRICE),2)))

iif((compare(TABLENAME,"PurchLine")>0),"SO","PO")

Agreegate: first('fieldname')

Filter On: TABLENAME == "VendTable"

Address street (3 fields)
Derived column1:
Address1-> split(STREET, "\n")

Derived column2:
Address1 ->
replace(iif(length(STREET) > 100, substring(STREET,1, 100), Address1[1]),'\n',' ')

Address2 ->replace(iif(length(STREET) > 100, substring(STREET,101, 100), iif(size(Address1) > 1,Address1[2], '')),'\n',' ')

Address3 ->replace(iif(length(STREET) > 200, substring(STREET,201, 100), iif(size(Address1 ) > 2,Address1 [3], '')),'\n',' ')

substring: (replace .csv to .zip)
@concat(
    substring(
        dataset().p_fileName,
        0,
        sub(
            length(dataset().p_fileName)
            ,4)
    ),'.zip'
)
Replace -> replace(toString(DATE,'YYYY-MM-DD'),'00:00:00','')

Dataset:
UTF-8 (format by D365FO DMF)

Friday, December 2, 2022

Auto Approve purchTable X++ in D365FO

 VersioningPurchaseOrder versioningPurchaseOrder;


        if (_PurchTable.ChangeRequestRequired)

        {

            versioningPurchaseOrder = VersioningPurchaseOrder::newPurchaseOrder(_PurchTable);

            versioningPurchaseOrder.submitChangeRequest();

            versioningPurchaseOrder.approveChangeRequest();

        }

Wednesday, October 12, 2022

To add dynamics default controls on UI in D365FO

 Reference Class:

SysSystemDefinedButtons


Sample code:

[ExtensionOf(classStr(SysSystemDefinedButtons))]

internal final class SysSystemDefinedButtonsCls_SAN_Extension

{

    private static str SANDE_SystemDefinedButtonsActionPane = "SystemDefinedButtonsActionPane";

    private static str SAN_SystemDefinedButtonsActionPane = "SAN_SystemDefinedButtonsActionPane";

    private static str SAN_SystemDefinedFormButtonGroup = "SAN_SystemDefinedButtonsButtonGroup_Form";

    private static str SAN_SystemDefinedWorkFlowButton = "SAN_SystemDefinedButtonWorkflow";

    private static str SAN_SystemDefinedWorkdlowActionPaneTab = "SAN_SystemDefinedWorkflow";

    private static str SAN_SystemDefinedWorkflowGroup = "SAN_SystemDefinedWorkflowGroup";


    public void addSystemDefinedButtons()

    {

        next addSystemDefinedButtons();


        if (this.isFormStyleSupportedForSystemDefinedButtons())

        {

            FormActionPaneControl actionPane;

            List listOfActionPanes;

            ListEnumerator apListEnumerator;


            listOfActionPanes = this.san_GetActionPanesForSystemButtons();

            apListEnumerator = listOfActionPanes.getEnumerator();


            while (apListEnumerator.moveNext())

            {

                actionPane = apListEnumerator.current();

                this.san_AddButtonsToActionPane(actionPane);

            }

            

        }

    }


    private List san_GetActionPanesForSystemButtons()

    {

        List listOfActionPanes = new List(Types::Class);

        FormActionPaneControl actionPane;

        Object childControl;

        FormRun form = this.getFormRun();

        

        for (int i = 1; i <= form.design().controlCount(); i++)

        {

            childControl = form.design().controlNum(i);


            if (classidget(childControl) == classnum(FormActionPaneControl))

            {

                actionPane = childControl as FormActionPaneControl;


                if (actionPane.Style() == ActionPaneStyle::Standard)

                {

                    listOfActionPanes.addEnd(actionPane);

                }

            }

        }


        if (listOfActionPanes.empty())

        {

            actionPane = form.design().addControl(FormControlType::ActionPane, SANDE_SystemDefinedButtonsActionPane);

            form.design().moveControl(actionPane.id());


            listOfActionPanes.addEnd(actionPane);

        }


        return listOfActionPanes;

    }


    private void san_AddButtonsToActionPane(FormActionPaneControl _actionPane)

    {

        FormButtonGroupControl buttonGroup;

        FormMenuButtonControl menuButton;

        FormCommandButtonControl commandButton;

        FormRun formRun = this.getFormRun();


        if (this.getFormStyle() != FormStyle::Workspace)

        {

            this.SAN_AddWorkflowsTab(_actionPane);

        }

    }


    private void SAN_AddWorkflowsTab(FormActionPaneControl _actionPane)

    {

        FormButtonGroupControl buttonGroup;

        FormMenuButtonControl menuButton;

        FormActionPaneTabControl workflowTab = _actionPane.addControl(FormControlType::ActionPaneTab, this.SAN_CreateUniqueName(SAN_SystemDefinedWorkdlowActionPaneTab));

        workflowTab.allowUserSetup(FormAllowUserSetup::No);

        FormRun form = this.getFormRun();


        workflowTab.caption("Custom Workflow");

        workflowTab.hideIfEmpty(true);


        buttonGroup = workflowTab.addControl(FormControlType::ButtonGroup, this.SAN_CreateUniqueName("SAN_SystemDefinedWorkflowGroup"));

        buttonGroup.allowUserSetup(FormAllowUserSetup::No);

        buttonGroup.caption("Workflow");


        FormFunctionButtonControl menuItemButton = buttonGroup.addControl(FormControlType::MenuFunctionButton, "SAN_WorflowButton", buttonGroup);

        menuItemButton.menuItemType(MenuItemType::Display);

        menuItemButton.menuItemName(menuItemDisplayStr(<Display menu item>));

        menuItemButton.dataSource(form.dataSource());

        menuItemButton.visible(true);

    }


    private str SAN_CreateUniqueName(str baseControlName)

    {

        str candidateName = baseControlName;

        int i = 1;


        if(this.SAN_isControlFound(candidateName))

        {

            do

            {

                candidateName = strFmt("%1%2", baseControlName, i);

                i++;

            }

            while (this.SAN_isControlFound(candidateName));

        }

        

        return candidateName;

    }


    private boolean SAN_isControlFound(str controlName)

    {

        FormRun form = this.getFormRun();


        boolean isControlFound = false;


        if (form.controlId(controlName) > 0)

        {

            isControlFound = true;

        }

              

        return isControlFound;

    }


}

Friday, October 7, 2022

Globals in D365FO (Implementation samples)

Samples


/// <summary>

    /// Convert the date input value to the string format YYYYMMDD.

    /// </summary>

    /// <param name="_input">Date input value; use today's date, if input is empty.</param>

    /// <returns>Returns the date input value in the string format YYYYMMDD.</returns>

    public static str YYYYMMDD(Date _input = DateTimeUtil::date(DateTimeUtil::getSystemDateTime()))

    {

        str dateString;

        

        dateString  = date2str(_input,

                                321,

                                DateDay::Digits2,

                                DateSeparator::None,

                                DateMonth::Digits2,

                                DateSeparator::None,

                                DateYear::Digits4);


        return dateString;

    }


    /// <summary>

    /// Convert the time input value to the string format hhmmss.

    /// </summary>

    /// <param name="_input">Time input value; use the current time, if the input is empty.</param>

    /// <returns>Returns the time input value in the string format hhmmss.</returns>

    public static str hhmmss(TimeOfDay _input = DateTimeUtil::time(DateTimeUtil::getSystemDateTime()))

    {

        str timeValue;

        str timeString;

        

        timeValue   = time2str( _input,

                            TimeSeparator::Dot,

                            TimeFormat::Hour24);


        timeString  =   substr(timeValue,1,2) +

                    substr(timeValue,4,2) +

                    substr(timeValue,7,2);


        return  timeString;

    }


    /// <summary>

    /// Convert the date and time input to the string format YYYYMMDD_hhmmss.

    /// </summary>

    /// <param name="_input">Date and time input value; use the current system date and time, if the input is empty.</param>

    /// <returns>Returns the date and time input in the string format YYYYMMDD_hhmmss.</returns>

    public static str YYYYMMDD_hhmmss(utcdatetime _dateTime = DateTimeUtil::getSystemDateTime())

    {

        Date        dateValue;

        TimeOfDay   timeValue;

        

        dateValue = DateTimeUtil::date(_dateTime);

        timeValue = DateTimeUtil::time(_dateTime);


        return strfmt('%1_%2', Global::YYYYMMDD(dateValue), Global::hhmmss(timeValue));

    }


    /// <summary>

    /// Convert the date and time input to the string format YYMMDD.

    /// </summary>

    /// <param name="_input">Date and time input value; use the current system date and time, if the input is empty.</param>

    /// <returns>Returns the date and time input in the string format YYMMDD.</returns>

    static str YYMMDD(Date _input = DateTimeUtil::date(DateTimeUtil::getSystemDateTime()))

    {

        str dateString;

        

        dateString  = date2str(_input,

                                321,

                                DateDay::Digits2,

                                DateSeparator::None,

                                DateMonth::Digits2,

                                DateSeparator::None,

                                DateYear::Digits2);


        return dateString;

    }


    public static date getCompanyDate(utcdatetime _input = DateTimeUtil::utcNow())

    {

        return DateTimeUtil::date(DateTimeUtil::applyTimeZoneOffset(_input, DateTimeUtil::getCompanyTimeZone()));

    }


    static str removeTabLineBreaks(str _input)

    {

        #File


        _input  = strreplace(_input, #delimiterEnter, #delimiterSpace);

        _input  = strreplace(_input, #delimiterTab, #delimiterSpace);

        _input  = strreplace(_input, #delimiterCRLF, #delimiterSpace);


        return _input;

    }


public static void setVisibilityForControls(FormRun _formrun, List _listOfControls, boolean isVisible)

    {

        if (_formrun && _listOfControls && !_listOfControls.empty())

        {

            ListIterator iterator = new ListIterator(_listOfControls);

            while(iterator.more())

            {

                FormControlName controlName = iterator.value();

                FormControl control = Global::getFormControl(_formrun, controlName);

                if (Control)

                {

                    control.visible(isVisible);

                }


                iterator.next();

            }

        }

    }


    private static FormControl getFormControl(FormRun _formrun, FormControlName _controlName)

    {

        return _formrun != null ? _formrun.control(_formrun.controlId(_controlName)) : null;

    }



Friday, September 9, 2022

Online store transaction new field flow to Sales order in D365FO

Set extension property for commerce order 

using Microsoft.Dynamics.Commerce.Runtime.Services.CustomerOrder;

using Microsoft.Dynamics.Commerce.Runtime.DataModel;

/// <summary>

/// Extension of <b>RetailTransactionTransformer</b> class

/// </summary>

[ExtensionOf(classStr(RetailTransactionTransformer))]

final class RetailTransactionTransformerCls_POL_Extension

{

/// <summary>

    /// Convert retail sales transaction into <b>ItemInfo</b> object

    /// </summary>

    public static ItemInfo ReadOneTransactionSalesTrans(RetailTransactionTable transactionTable, RetailTransactionSalesTrans salesTrans)

    {

        ItemInfo itemInfo = next ReadOneTransactionSalesTrans(transactionTable, salesTrans);

        ExtensionPropertyCollection extensionPropertyCollection = itemInfo.ExtensionProperties;

        CommerceProperty splitPropery = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionSalesTrans, <CustomField>), enum2int(salesTrans.<CustomField>));

        CommerceProperty comment            = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionSalesTrans, comment), salesTrans.comment);

        extensionPropertyCollection.Add(splitPropery );

        extensionPropertyCollection.Add(comment);

        return itemInfo;

    }


    /// <summary>

    /// This method is used to read sales transactions for return.

    /// </summary>

    public static ItemInfo ReadOneTransactionSalesTransForReturn(

                RetailTransactionTable transactionTable,

                RetailTransactionSalesTrans salesTrans)

    {

        ItemInfo itemInfo = next ReadOneTransactionSalesTransForReturn(transactionTable, salesTrans);


        ExtensionPropertyCollection extensionPropertyCollection = itemInfo.ExtensionProperties;


        CommerceProperty customLineNumber   = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionSalesTrans, customPortalLineNum), salesTrans.customPortalLineNum);        

        extensionPropertyCollection.Add(customLineNumber   );

        return itemInfo;

    }


    /// <summary>

    /// Convert a transaction data into customer order info.

    /// </summary>

    public static CustomerOrderInfo ConvertTransactionToCustomerOrderInfo(RetailTransactionTable transactionTable)

    {

        CustomerOrderInfo customerOrderInfo =  next ConvertTransactionToCustomerOrderInfo(transactionTable);

        var extensionPropertyCollection = customerOrderInfo.ExtensionProperties;

        CommerceProperty custPurchaseOrder  = new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionTable, CustPurchaseOrder), transactionTable.CustPurchaseOrder);

        CommerceProperty  isImport= new Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty(fieldStr(RetailTransactionTable, isImport), enum2Str(transactionTable.isImport));        

        extensionPropertyCollection.Add(custPurchaseOrder);

        extensionPropertyCollection.Add(isImport);

        return customerOrderInfo;

    }

}


using Microsoft.Dynamics.Commerce.Runtime.Services.CustomerOrder;

/// <summary>

    /// To update sales order while creating through sync orders from retail

    /// </summary>

    [SubscribesTo(classStr(RetailTransactionServiceOrders), staticDelegateStr(RetailTransactionServiceOrders, beforeCreatingRetailOrderLines))]

    public static void RetailTransactionServiceOrders_beforeCreatingRetailOrderLines(SalesTable _salesTable, Microsoft.Dynamics.Commerce.Runtime.Services.CustomerOrder.CustomerOrderInfo _customerOrderInfo)

    {

        var extensionPropertyCollection = _customerOrderInfo.ExtensionProperties;

        Microsoft.Dynamics.Commerce.Runtime.DataModel.CommercePropertyValue propertyValue;

        boolean                 update = false;

        for (int i=0; i < extensionPropertyCollection.get_Count(); i++)

        {

            var commerceProperty = extensionPropertyCollection.get_Item(i) as Microsoft.Dynamics.Commerce.Runtime.DataModel.CommerceProperty;

            switch(commerceProperty.Key)

            {

                case fieldStr(RetailTransactionTable, custPurchaseOrder):

                     propertyValue = commerceProperty.Value;

                    _salesTable.PurchOrderFormNum = propertyValue.StringValue;

                    update = true;

                    break;

                case fieldStr(RetailTransactionTable, <CustomField>): //Enum

                    propertyValue = commerceProperty.Value;

                    NoYesId noYesId;

                    _salesTable.<CustomField> = str2Enum(noYesId,propertyValue.StringValue);

                    update = true;

                    break;

                case fieldStr(RetailTransactionTable, <CustomField>):

                    propertyValue = commerceProperty.Value;

                     _salesTable.<CustomField>= propertyValue.StringValue;

                    break;

            }

             

        }

        if(update)

        {

            _salesTable.doUpdate();

        }

    }

Thursday, September 8, 2022

Power Automate (Flow) Expression usage samples


Get list items from Array

item()?['weborder']

Get compose output body content

outputs('Get_file_content')?['body']

Get Blob content

outputs('Get_blob_content_using_path_(V2)')?['body']

outputs('Get_blob_content_using_path_(V2)')?['value']


Split string by comma

split(variables('<var name>'),',')


Decode CSV file from Blob DECODE URI:

split(outputs('Get_blob_content_using_path_(V2)')?['body'], decodeUriComponent('%0D%0A'))

Skip output line 1

skip(outputs('splitNewLine'),2)

Get output value from list

outputs('OutputJSON')?['WebOrderNo']

outputs('D365FOSelectOut')?['body']

Find length of array

length(body('D365FOSelectOut'))

Concat string

concat(variables('OutputArrayResult'),outputs('D365FOSelectOut')?['body'])

Append array variables (Reference Blog) using Append to array variable (Action)

https://www.enjoysharepoint.com/power-automate-array-variable/

Get output Body/Value

outputs('Lists_items_present_in_table')?['body/value']

Date time format: (Reference Blog)
https://sharepains.com/2018/11/12/formatdatetime-power-automate/


Convert: (while using HTTP request output content type is octet stream, but excepted should be in Text/csv. Follow below

Header; Add in addition to existing header
"x-ms-access-tier-inferred": true

output:
{
"$content-type":  "application/octet-stream",
"$content":  "Ww0KICB7DQogICCJyZWNlaXZlciI6ICIgMTIzODUiLA0KICAgICJwYXlsb2FkIjogIiB7J21lc3NhZ2UnOiAndGVzdCAxJyIsDQogICAgIm9wZXJhdG9yIjogIiAnRW5naW5lSWQnOiAzIiwNCiAgICAic2VuZGVyIjogIiAnUGVyc29uSWQnOiAxIg0KICB9LA0KICB7DQogICAgImlkIjogIjIiLA0KICAgICJyZWNlaXZlciI6ICIgMTIzNDciLA0KICAgICJwYXlsb2FkIjogIiB7J21lc3NhZ2UnOiAndGVzdCAyJyIsDQogICAgIm9wZXJhdG9yIjogIiAnRW5naW5lSWQnOiAzIiwNCiAgICAic2VuZGVyIjogIiAnUGVyc29uSWQnOiAyIg0KICB9DQpd"
}

then we use

string(triggerBody()) ex: string(outputs('HTTPGetBlobContent')?['body'])

Date difference:
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),864000000000)
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),36000000000)
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),600000000)
div(sub(ticks({EndDateTime}),ticks({StartDateTime})),10000000)

Wednesday, August 17, 2022

To extend the constructor to instantiate the extended (Custom) class in D365FO


    [PostHandlerFor(classStr(<Std class name>), staticMethodStr(<Std class name>, construct))]

    public static void <Std class name>_Post_construct(XppPrePostArgs args)

    {

        <Std class name>  objCls;

        objCls= args.getReturnvalue();       

        args.setReturnValue(<Custom class name>::construct(args.getArg(identifierStr(<Argument name>)),args.getArg(identifierStr(<Argument name>))));

    }

Wednesday, July 27, 2022

Monday, July 25, 2022

Useful script for D365FO

 


Reference:

https://github.com/TrudAX/TRUDScripts/blob/master/D365FO/UsefulScripts.ps1


List:

https://github.com/d365collaborative/d365fo.tools/wiki

#MaintenanceMod

#SYNC

#INSTALL LICENCE 

#DOWNLOAD DB FROM LCS

#BACKUP TIER1

#RESTORE TIER1 DB on TIER1

#SQL update userinfo set enable= 1

#TRANSFER TO TIER2

#DEPLOY REPORTS

#RESTORE TIER2 TO TIER1

#prepare the database

#IMPORT USERS

#RUN JOB

Tuesday, July 5, 2022

Batch job clean up X++ D365FO

  Connection                      connection;

        Statement                       statement;

        SqlStatementExecutePermission   permission;

        str                             deleteStm;


        if (!Global::isSystemAdministrator())

        {

            error("@SYS130561");

            return;

        }


        connection  = new Connection();

        connection.ttsbegin();


        statement   = connection.createStatement();

        deleteStm = '(SELECT RECID FROM ' + ReleaseUpdateDB::backendTableName(tableNum(Batch)) + ' WHERE GROUPID = \'' + 'TT_BT' + '\')';

        deleteStm = 'DELETE FROM ' + ReleaseUpdateDB::backendTableName(tableNum(BatchConstraints)) + ' WHERE BATCHID IN ' + deleteStm +

            ' OR DEPENDSONBATCHID IN ' + deleteStm + ';';

        permission  = new SqlStatementExecutePermission(deleteStm);

        permission.assert();

        statement.executeUpdate(deleteStm);

        statement.close();

        CodeAccessPermission::revertAssert();


        statement   = connection.createStatement();

        deleteStm = 'DELETE FROM ' + ReleaseUpdateDB::backendTableName(tableNum(Batch)) + ' WHERE GROUPID = \'' + 'TT_BT' + '\';';

        permission  = new SqlStatementExecutePermission(deleteStm);

        permission.assert();

        statement.executeUpdate(deleteStm);

        statement.close();

        CodeAccessPermission::revertAssert();


statement   = connection.createStatement();

        deleteStm = 'DELETE FROM ' + ReleaseUpdateDB::backendTableName(tableNum(BatchJobHistory)) + ' WHERE STATUS != \'' + 3 + '\';';

        permission  = new SqlStatementExecutePermission(deleteStm);

        permission.assert();

        statement.executeUpdate(deleteStm);

        statement.close();

        CodeAccessPermission::revertAssert();


        connection.ttscommit();

        connection = null;

Wednesday, June 22, 2022

Postman Odata request for filters and Pre request script for dates

Postman: (Get request time rely on server timezone)

Request: GET ->

https://<D365FO URL>/data/BatchJobs?$filter=Status eq Microsoft.Dynamics.DataEntities.BatchStatus'Executing' and StartDate eq {{currentdate}} and StartTime gt {{currentTime}} &cross-company=true


or

https://<D365FO URL>/data/RetailTransactions?$filter=ChannelReferenceId eq '' and CustomerAccount eq '' and TransactionDate eq 2022-08-23 &cross-company=true


Pre-Request script:

var moment = require('moment');

pm.globals.set('currentdate', moment().format(("YYYY-MM-DD")));

pm.globals.set("currentTime"new Date().setTime(new Date().getTime()-10800)); (As per postman installed machine time Zone GMT)

//setting

postman.setEnvironmentVariable("currentdate", moment().format(("YYYY-MM-DD")));


Set Global variables:

var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("access_token"jsonData.access_token);

Select field list
&$select=CustomerAccount,OrganizationName

Test samples:
pm.test("Status code is 200"function () {
    pm.response.to.have.status(200);
});
var json = JSON.parse(responseBody);
tests["<Collection request name>"= !json.error && responseBody !== '' && responseBody !== '{}' && json.Id !== '';
postman.setEnvironmentVariable("<Global variable name>"json.AmountDue);

var json = JSON.parse(responseBody);
tests["<Collection request name>"= !json.error && responseBody !== '' && responseBody !== '{}' && json.CartLines !== '';
postman.setEnvironmentVariable("<Global variable name>"json.CartLines[0].LineId);

Upload data from Excel in D365FO X++

 Action Menu Item: SAN_UploadExcelData Object type: Class Object: <Controller class name> Label: <> Class: Controller class clas...