Wednesday, May 14, 2025

Upload file CSV/TXT using SysOperation in D365 X++

Upload CSV/TXT using SysOperation X++


Contract:
/// <summary>
/// Contract class upload through excel for PO inbound journals
/// </summary>
[DataContractAttribute,
    SysOperationContractProcessingAttribute(classStr(SAN_POImportUIBuilder))]
public class SAN_POImportContract extends SysOperationDataContractBase 
                    Implements SysOperationInitializable, SysOperationValidatable
{
    FileName                    fileName;
    private System.IO.Stream    inputDataStream;
    NoYes                       hasColumnNames;
    Str1260                     layout;

    /// <summary>
    /// Validates the parameters.
    /// </summary>
    /// <returns>
    /// true if successful; otherwise, false.
    /// </returns>
    public boolean validate()
    {
        return true;
    }

    public void initialize()
    {
        hasColumnNames = NoYes::Yes;
    }

    /// <summary>
    /// Gets or sets the value of the data contract parameter fileName.
    /// </summary>
    /// <param name="_fileName">
    /// The new value of the data contract parameter fileName.
    /// </param>
    /// <returns>
    /// Returns the current value of data contract parameter fileName.
    /// </returns>
    public Filename parmFileName(FileName _fileName = fileName)
    {
        fileName = _fileName;
        return fileName;
    }

    /// <summary
    /// Gets or sets the value of the data contract parameter hasColumnNames.
    /// </summary>
    /// <param name = "_hasColumnNames">
    /// The new value of the data contract parameter hasColumnNames.
    /// </param>
    /// <returns>
    /// Returns the current value of data contract parameter hasColumnNames.
    /// </returns>
    [DataMemberAttribute,
        SysOperationLabelAttribute("File has header column") ]
    public NoYes parmHasColumnNames(NoYes _hasColumnNames = hasColumnNames)
    {
        hasColumnNames = _hasColumnNames;
        return hasColumnNames;
    }

    /// <summary>
    /// Set or get Input file data stream
    /// </summary>
    /// <param name = "_value">current value of stream</param>
    /// <returns>file memory stream to process</returns>
    [Hookable(false)]
    public System.IO.Stream parmInputDataStream(System.IO.Stream _value = inputDataStream)
    {
        inputDataStream = _value;
        return inputDataStream;
    }

    /// <summary>
    /// Gets or sets the value of the data contract parameter fileLayout.
    /// </summary>
    /// <param name="_layout">
    /// The new value of the data contract parameter fileLayout.
    /// </param>
    /// <returns>
    /// Returns the current value of data contract parameter fileLayout.
    /// </returns>
    [DataMemberAttribute,
        SysOperationLabelAttribute("File layout") ]
    public Str1260 parmLayout(Str1260 _layout = layout)
    {
        layout =  '';
        layout =  'TXT/CSV File delimited as |' + '\n';

        layout += strfmt("%1 | %2 : %3\n", '1', 'A', 'Column1');
        layout += strfmt("%1 | %2 : %3\n", '2', 'B', 'Column2');
        layout += strfmt("%1 | %2 : %3\n", '3', 'C', 'Column3');
        layout += strfmt("%1 | %2 : %3\n", '4', 'D', 'Column4');
        layout += strfmt("%1 | %2 : %3\n", '5', 'E', 'Column5');


        return layout;
    }

}

UI Builder:
/// <summary>
/// Class is to upload through excel for PO inbound substitution journals to handle run time contract operations
/// </summary>
class SAN_POImportUIBuilder extends SysOperationAutomaticUIBuilder
{

    #define.commandButton('CommandButton')
    #define.fileUpload('FileUpload')
    #define.fileTypesAccepted('.txt,.csv')
    
    SAN_POImportContract   contract;

    /// <summary>
    /// Adds a button to the dialog to import a file.
    /// </summary>
    [Hookable(false)]
    public void build()
    {
        DialogGroup             dialogGroup;
        DialogTabPage           dialogTabPage;
        Dialog                  dlg;
        FormBuildControl        formBuildControl;
        FileUploadBuild         dialogFileUpload;
        DialogField             dialogLayout;
        FormBuildTabPageControl parametersTabPage;
        FormBuildTabPageControl layoutTabPage;

        dlg = this.dialog();

        contract = this.dataContractObject() as SAN_POImportContract;

        dialogTabPage = dlg.addTabPage("@SYS7764");
        dialogTabPage.columns(2);
        parametersTabPage = dlg.formBuildDesign().control(dialogTabPage.name());
        parametersTabPage.fastTabExpanded(FastTabExpanded::Yes);
        dialogGroup = dlg.addGroup('Upload file');
        formBuildControl = dlg.formBuildDesign().control(dialogGroup.name());
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), #fileUpload);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted(#fileTypesAccepted);
        dialogFileUpload.fileNameLabel("@SYS308842");

        dlg.addGroup("@SYS339526");
        this.addDialogField(methodStr(SAN_POImportContract, parmHasColumnNames), contract);

        dialogTabPage = dlg.addTabPage("@Polaris:FileLayout");
        layoutTabPage = dlg.formBuildDesign().control(dialogTabPage.name());
        layoutTabPage.fastTabExpanded(FastTabExpanded::Yes);
        dialogLayout = this.addDialogField(methodStr(SAN_POImportContract, parmLayout), contract);
        dialogLayout.showLabel(false);
        dialogLayout.enabled(false);
        dialogLayout.widthMode(1);
        dialogLayout.displayHeight(15);
    }

    /// <summary>
    /// Handles dialog closing events.
    /// </summary>
    /// <param name = "sender">
    /// xFormRun class.
    /// </param>
    /// <param name = "e">
    /// FormEventArgs class.
    /// </param>
    [SuppressBPWarningAttribute('BPParametersNotUsed', 'This event parameter is not used')]
    private void dialogClosing(xFormRun sender, FormEventArgs e)
    {
        FormEventArgs formEventArgs;

        formEventArgs = e;

        this.dialogEventsUnsubscribe(sender as FormRun);
    }

    /// <summary>
    /// Handles dialog events.
    /// </summary>
    /// <param name = "_formRun">
    /// FormRun class type.
    /// </param>
    private void dialogEventsSubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(#fileUpload));
        fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted += eventhandler(this.uploadStarted);
        _formRun.onClosing += eventhandler(this.dialogClosing);
    }

    /// <summary>
    /// Handles dialog event.
    /// </summary>
    /// <param name = "_formRun">
    /// FormRun class type.
    /// </param>
    private void dialogEventsUnsubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(#fileUpload));
        fileUpload.notifyUploadCompleted -= eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted -= eventhandler(this.uploadStarted);
        _formRun.onClosing -= eventhandler(this.dialogClosing);
    }

    /// <summary>
    /// Handles dialog event post run.
    /// </summary>
    [Hookable(false)]
    public void postRun()
    {
        super();
        FormRun formRun = this.dialog().dialogForm().formRun();
        this.dialogEventsSubscribe(formRun);
        this.setDialogOkButtonEnabled(formRun, false);
    }

    /// <summary>
    /// Enables or disables the dialog Ok button.
    /// </summary>
    /// <param name = "_formRun">
    /// The <c>FormRun</c> object.
    /// </param>
    /// <param name = "_isEnabled">
    /// Indicates to enable or disable the Ok button.
    /// </param>
    protected void setDialogOkButtonEnabled(FormRun _formRun, boolean _isEnabled)
    {
        FormControl okButtonControl = _formRun.control(_formRun.controlId(#commandButton));
        if (okButtonControl)
        {
            okButtonControl.enabled(_isEnabled);
        }
    }

    /// <summary>
    /// After the file has been uploaded, the Ok button is enabled.
    /// </summary>
    protected void uploadCompleted()
    {
        contract = this.dataContractObject() as SAN_POImportContract;
        var formRun = this.dialog().dialogForm().formRun();
        FileUpload fileUpload = formRun.control(formRun.controlId(#fileUpload));

        contract.parmFileName(fileUpload.fileName());
        using (System.IO.Stream stream = fileUpload.getUploadedFile(true))
        {
            if (stream)
            {
                System.IO.MemoryStream copiedStream = new System.IO.MemoryStream();
                stream.CopyTo(copiedStream);
                
                contract.parmInputDataStream(copiedStream);
            }
        }

        this.setDialogOkButtonEnabled(formRun, contract.parmInputDataStream() != null);
    }

    /// <summary>
    /// During file upload, the Ok button is disabled.
    /// </summary>
    private void uploadStarted()
    {
        var formRun = this.dialog().dialogForm().formRun();
        this.setDialogOkButtonEnabled(formRun, false);
    }

}


Controller:
/// <summary>
/// Class is to handle controller logic to upload  PO journals
/// </summary>
class SAN_POImportController extends SysOperationServiceController
{
    public ClassDescription caption()
    {
        return "Upload  Purchase Journals";
    }

    /// <summary>
    /// Provides entry point for the instance of <c>SAN_POImportController</c>.
    /// </summary>
    /// <param name = "_args">
    /// The arguments passed to the class <c>SAN_POImportController</c>.
    /// </param>
    public static void main(Args _args)
    {
        SAN_POImportController controller;

        controller = SAN_POImportController::construct();
        controller.showBatchTab(false);
        controller.parmArgs(_args);
        controller.startOperation();
    }

    /// <summary>
    /// Initializes new instance of <c>SAN_POImportController</c>.
    /// </summary>
    /// <returns>
    /// Return object of <c>SAN_POImportController</c>.
    /// </returns>
    public static SAN_POImportController construct()
    {
        SAN_POImportController   controller;
        
        controller = new SAN_POImportController(classStr(SAN_POImportService),
                                                        methodStr(SAN_POImportService, Run),
                                                        SysOperationExecutionMode::Synchronous);

        return controller;
    }

}

Service:
/// <summary>
/// Class is to upload through excel for PO upload journals to handle service operations
/// </summary>
class SAN_POImportService extends SysOperationServiceBase
{
    System.IO.Stream                        stream;
    int                                     totalLinesProcessed = 0;
    SAN_POImportContract        contract;
    str                             filename, journalProcessId;

    /// <summary>
    /// process file to upload WG purchase line item substitution journals
    /// </summary>
    /// <param name = "_contract">
    /// Contract class.
    /// </param>
    public void run(SAN_POImportContract _contract)
    {
        contract            = _contract;
        stream              = _contract.parmInputDataStream();
        filename            = _contract.parmFileName();
        this.processFile(_contract);
    }

    /// <summary>
    /// Processing excel file input
    /// </summary>
    /// <param name = "_contract">
    /// Contract class.
    /// </param>
    protected void processFile(SAN_POImportContract _contract)
    {
        #File
        TextStreamIo inFile = TextStreamIo::constructForRead(stream);
        inFile.inFieldDelimiter('|'); //TODO delimiter used
        inFile.inRecordDelimiter('\r\n'); 
        container recordContainer;
        str item;
        boolean     isFirstLine = true;
        recordContainer = inFile.read();
        if(_contract.parmHasColumnNames())
        {
            recordContainer = inFile.read();
        }
        
        ttsbegin;
        while (inFile.status() == IO_Status::OK)
        {
            if(isFirstLine)
            {
journalProcessId = '';
                //Header record creation logic
                isFirstLine= false;
            }

           //line record creation logic
            //Read the next line
            recordContainer = inFile.read();
        }
        ttscommit;

        info(strFmt("Journal - %2 Total record lines created %1",totalLinesProcessed, journalProcessId));
    }

}

Tuesday, April 15, 2025

OData Batch request API - D365FO

 --batch_MultipleInvoices

Content-Type: multipart/mixed;boundary=changeset_123


--changeset_123

Content-Type: application/http

Content-Transfer-Encoding: binary


POST https://<d365fourl>/data/PortalSalesDocuments/Microsoft.Dynamics.DataEntities.getSalesInvoice HTTP/1.1

Content-Type: application/json

Content-ID: 1


{

    "invoiceId": "SIAA00026",

    "dataAreaId": "usmf"

}

--changeset_123

Content-Type: application/http

Content-Transfer-Encoding: binary


POST https://<d365fourl>/data/PortalSalesDocuments/Microsoft.Dynamics.DataEntities.getSalesInvoice HTTP/1.1

Content-Type: application/json

Content-ID: 2


{

    "invoiceId": "SIAA00047",

    "dataAreaId": "usmf"

}

--changeset_123--

--batch_MultipleInvoices--

Friday, March 21, 2025

Disabling the flight in D365FO (CHD - Tier 1)

 INSERT INTO dbo.SYSFLIGHTING(FLIGHTNAME, ENABLED) 

VALUES ('<FlightObjectName>_KillSwitch', 1)

 or 

INSERT INTO dbo.SYSFLIGHTING(FLIGHTNAME, ENABLED) 

VALUES ('<FlightObjectName>', 0)

Monday, March 17, 2025

Get unicode character in excel

 Excel formula


=AND(ISTEXT(C2),SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(LOWER(C2),"a",),"b",),"c",),"d",),"e",),"f",),"g",),"h",),"i",),"j",),"k",),"l",),"m",),"n",),"o",),"p",),"q",),"r",),"s",),"t",),"u",),"v",),"w",),"x",),"y",),"z",),"-",),",",),"",),"0",),"1",),"2",),"3",),"4",) ,"5",),"6",),"7",),"8",),"9",),"&",),")",),"(",),".",),"/",),"–",),"#",),"*",),"'",),"+",),":",),";",),"$",),"%",)= "")

Wednesday, February 19, 2025

Validate product from Retail Assortment in D365FO X++

Public boolean SAN_validateProductAssortment(Str    _itemId)

{

    RetailAssortmentTable           retailAssortmentTable;

    RetailChannelAssortedProductView  retailChannelAssortedProductView;

    InventTable                       inventTable;

    while select  retailAssortmentTable

    {

            select firstonly retailChannelAssortedProductView

                 exists join inventTable

                where inventTable.ItemId == _itemId

                  && retailChannelAssortedProductView.AssortmentRecId == retailAssortmentTable.RecId

                  && retailChannelAssortedProductView.ProductID == inventTable.Product

                  && retailChannelAssortedProductView.InventLocationDataAreaId == inventTable.DataAreaId;

            if(retailChannelAssortedProductView)

            {

                return true;

            }

        }


    }

    throw Error("Invalid item to sell based on assortments");

Monday, January 6, 2025

Search hierarchy for a match (TableALLGroup) X++

  Table1 ppt;


 select firstonly ppt

 order ItemCode, ItemRelation, AccountCode, AccountRelation where

     (ppt.ItemCode == TableGroupAll::Table && ppt.ItemRelation == _itemId &&

         ppt.AccountCode == TableGroupAll::Table && ppt.AccountRelation == _accountNum) ||

     (ppt.ItemCode == TableGroupAll::Table && ppt.ItemRelation == _itemId &&

         ppt.AccountCode == TableGroupAll::GroupId && ppt.AccountRelation == _accountGroup) ||

     (ppt.ItemCode == TableGroupAll::Table && ppt.ItemRelation == _itemId &&

         ppt.AccountCode == TableGroupAll::All && ppt.AccountRelation == '') ||


     (ppt.ItemCode == TableGroupAll::GroupId && ppt.ItemRelation == _ItemGroup &&

         ppt.AccountCode == TableGroupAll::Table && ppt.AccountRelation == _accountNum) ||

     (ppt.ItemCode == TableGroupAll::GroupId && ppt.ItemRelation == _ItemGroup &&

         ppt.AccountCode == TableGroupAll::GroupId && ppt.AccountRelation == _accountGroup) ||

     (ppt.ItemCode == TableGroupAll::GroupId && ppt.ItemRelation == _ItemGroup &&

         ppt.AccountCode == TableGroupAll::All && ppt.AccountRelation == '') ||


     (ppt.ItemCode == TableGroupAll::All && ppt.ItemRelation == '' &&

         ppt.AccountCode == TableGroupAll::Table && ppt.AccountRelation == _accountNum) ||

     (ppt.ItemCode == TableGroupAll::All && ppt.ItemRelation == '' &&

         ppt.AccountCode == TableGroupAll::GroupId && ppt.AccountRelation == _accountGroup) ||

     (ppt.ItemCode == TableGroupAll::All && ppt.ItemRelation == '' &&

         ppt.AccountCode == TableGroupAll::All && ppt.AccountRelation == '');


 // Return table buffer if found, otherwise return 0 as the default

 if (ppt.RecId)

 {

     // return result

 }

Thursday, January 2, 2025

Create call center channel users X++ D365FO

 RetailChannelTable   channelTable;

MCRChannelUser      channelUser;


while select channelTable

    where channelTable.ChannelType ==  RetailChannelType::MCRCallCenter

{

    channelUser.clear();

    changecompany(channelTable.DefaultCustDataAreaId)

    {

        channelUser = MCRChannelUser::find();


        if(!channelUser)

        {

            channelUser.clear();

            channelUser.initValue();

            channelUser.Channel = channelTable.RecId;

            channelUser.User = curUserId();

            channelUser.insert();

        }

    }           

}

Thursday, December 12, 2024

Convert Call stack to readable format in D365FO X++

//Input

--container _xppCallStack = xSession::xppCallStack(); 


Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFrames)

{

    str result = '';

    int startFrame = 1 + _skipFrames;


    // Each stack frame is four elements [Method, Line Number, Model Publisher, Model]

    for (int i = startFrame; i <= conLen(_xppCallStack); i += 4)

    {

        str methodName = conPeek(_xppCallStack, i);

        str lineNum = conPeek(_xppCallStack, i + 1);

        str publisher = conPeek(_xppCallStack, i + 2);

        str model = conPeek(_xppCallStack, i + 3);


        // Add a newline between stack frames

        if (i > 1)

        {

            result += '\n at';

        }

        

        // Model identifer

        if (publisher || model)

        {

            result += strFmt('[%1%2%3]', publisher, (publisher && model ? ':' : ''), model);

        }

        

        // Code

        result += strFmt('%1%2', methodName, (lineNum && lineNum != '0' ? ':' + lineNum : ''));

    }


    return result;

}

Monday, November 4, 2024

Copy Markup charges while posting purchase invoice using X++

 Copy Markup charges while posting purchase invoice using X++


Class:

Important: Code logic is just for Reference. 

New class => Duplicate of class MarkupCopy & Named as SAN_MarkupCopy

/// <summary>

/// Duplicate Copy class of MarkupCopy

/// Due to extension limited capabilities on internal and private implementation from STD OOB


Helper class: To call logic 

/// <summary>

/// Helper class to centralized logic to copy charges from and to table buffer for purchase

/// </summary>

class SAN_GeneratePurchaseMarkupChargesHelper

{

    public static void createPurchaseHeaderMarkupCharge(

                        Common          _fromTable, 

                        Common          _toTable,

                        PurchTable      _purchTable )

    {

        MarkupCopy                          markupCopy;

        MarkupCopyFromPurchOrderParameters  copyFromPurchOrderToSubTableParameters;


        markupCopy = MarkupCopy::construct();

        copyFromPurchOrderToSubTableParameters =

            MarkupCopyFromPurchOrderParameters::createCopyFromPurchOrderParameters(

                _fromTable,

                _toTable,

                '',

                _purchTable.CurrencyCode,

                SourceDocumentLineAccountingStatus::Draft,

                _purchTable,

                false);

        markupCopy.copyFromPurchOrder(copyFromPurchOrderToSubTableParameters);

    }


  public static void createPurchaseLinesMarkupCharge(

                        PurchLine          _purchLine,

                        VendInvoiceInfoLine          _vendInvoiceInfoLine,

                        PurchTable                  _purchTable,

                        VendInvoiceInfoTable    _vendInvoiceInfoTable)

    {

        ttsbegin;

        SAN_MarkupCopy markupCopy;


        markupCopy = SAN_MarkupCopy::construct();

        MarkupCopyFromPurchOrderParameters copyFromPurchOrderToLineParameters;

        

        copyFromPurchOrderToLineParameters =

                    MarkupCopyFromPurchOrderParameters::createCopyFromPurchOrderParameters(

                        _purchLine,

                        _vendInvoiceInfoLine,

                        '',

                        '',

                        SourceDocumentLineAccountingStatus::Draft,

                        null,

                        false);

        SysDaBinaryExpression       sysDaBinaryExpressionSource, sysDaBinaryExpressionDest;

        sysDaBinaryExpressionDest =  new SysDaEqualsExpression(

                new SysDaFieldExpression(_vendInvoiceInfoLine, fieldStr(VendInvoiceInfoLine, ParmId)), new SysDaValueExpression(_vendInvoiceInfoTable.ParmId))

            .and(new SysDaEqualsExpression(

                new SysDaFieldExpression(_vendInvoiceInfoLine, fieldStr(VendInvoiceInfoLine, TableRefId)), new SysDaValueExpression(_vendInvoiceInfoTable.TableRefId)));


        sysDaBinaryExpressionSource =  new SysDaEqualsExpression(

                new SysDaFieldExpression(_purchLine, fieldStr(PurchLine, RecId)), new SysDaFieldExpression(_vendInvoiceInfoLine, fieldStr(VendInvoiceInfoLine, PurchLineRecId)));


        copyFromPurchOrderToLineParameters.parmBufferToWhereClause(sysDaBinaryExpressionDest);

        copyFromPurchOrderToLineParameters.parmBufferFromWhereClause(sysDaBinaryExpressionSource);

        copyFromPurchOrderToLineParameters.parmDocumentStatusToExclude(DocumentStatus::Invoice);



        MarkupTransTmp markUpTransTmp = markupCopy.copyForAllDocumentLinesUsingTempMarkupTrans(copyFromPurchOrderToLineParameters);

        SAN_GeneratePurchaseMarkupChargesHelper::copyMarkupFromPurchOrderOptimizedCleanup(_vendInvoiceInfoTable, markUpTransTmp);


        ttscommit;

    }


    private static void copyMarkupFromPurchOrderOptimizedCleanup(VendInvoiceInfoTable _vendInvoiceInfoTable, MarkupTransTmp _markUpTransTmpCopy)

    {

        MarkupTrans markupTransOtherInvoices;

        VendInvoiceInfoLine vendInvoiceInfoLine;

        MarkupTransMapping markUpTransMapping;

        

        // Find if there is a MarkupTrans that is not marked Keep and it is already connected to another invoice

        // we will only call delete if there exists one

        select firstonly RecId from _markUpTransTmpCopy

        join vendInvoiceInfoLine

            where vendInvoiceInfoLine.ParmId == _vendInvoiceInfoTable.ParmId

                && vendInvoiceInfoLine.TableRefId == _vendInvoiceInfoTable.TableRefId

                && _markUpTransTmpCopy.TransTableId == vendInvoiceInfoLine.TableId

                && _markUpTransTmpCopy.TransRecId == vendInvoiceInfoLine.RecId

                && _markUpTransTmpCopy.SourceDocumentLine == 0

                && !_markUpTransTmpCopy.Keep

        join markupTransOtherInvoices

            where markupTransOtherInvoices.OrigTableId == _markUpTransTmpCopy.OrigTableId

                && markupTransOtherInvoices.OrigRecId == _markUpTransTmpCopy.OrigRecId

                && markupTransOtherInvoices.TransTableId == _markUpTransTmpCopy.TransTableId

                && markupTransOtherInvoices.TransRecId != _markUpTransTmpCopy.TransRecId;


        if (_markUpTransTmpCopy.RecId != 0)

        {

            vendInvoiceInfoLine.clear();

            markupTransOtherInvoices.clear();


            delete_from _markUpTransTmpCopy

            exists join vendInvoiceInfoLine

                where vendInvoiceInfoLine.ParmId == _vendInvoiceInfoTable.ParmId

                    && vendInvoiceInfoLine.TableRefId == _vendInvoiceInfoTable.TableRefId

                    && _markUpTransTmpCopy.TransTableId == vendInvoiceInfoLine.TableId

                    && _markUpTransTmpCopy.TransRecId == vendInvoiceInfoLine.RecId

                    && _markUpTransTmpCopy.SourceDocumentLine == 0

                    && !_markUpTransTmpCopy.Keep

            join markupTransOtherInvoices

                where markupTransOtherInvoices.OrigTableId == _markUpTransTmpCopy.OrigTableId

                    && markupTransOtherInvoices.OrigRecId == _markUpTransTmpCopy.OrigRecId

                    && markupTransOtherInvoices.TransTableId == _markUpTransTmpCopy.TransTableId

                    && markupTransOtherInvoices.TransRecId != _markUpTransTmpCopy.TransRecId;

        

            //Perform cascading delete action for <c>MarkupTransMapping</c> table

            markUpTransMapping.clear();


            markUpTransMapping.skipDataMethods(true);

            markUpTransMapping.skipDeleteActions(true);

            markUpTransMapping.skipEvents(true);


            delete_from markUpTransMapping

            notexists join _markUpTransTmpCopy

                where _markUpTransTmpCopy.TransRecId == markUpTransMapping.MarkupTransTransRecId &&

                    _markUpTransTmpCopy.TransTableId == markUpTransMapping.MarkupTransTransTableId &&

                    _markUpTransTmpCopy.LineNum == markUpTransMapping.MarkupTransLineNum;

        }


        // Create a SourceDocumentLine record for each new charge

        RecId sourceDocumentHeader = _vendInvoiceInfoTable.SourceDocumentHeader;

        int SourceRelationType = tableNum(MarkupTrans);

        EnumName TypeEnumName = enumStr(SourceDocumentLine_VendorInvoice);

        EnumValue TypeEnumValue = SourceDocumentLine_VendorInvoice::VendorInvoiceChargeLine;

        SourceDocumentLineAccountingStatus AccountingStatus = SourceDocumentLineAccountingStatus::Draft;

        AccountingDate ExchangeRateDate = _vendInvoiceInfoTable.updateDate();


        vendInvoiceInfoLine.clear();

        

        SourceDocumentLine sourceDocumentLine;

        

        sourceDocumentLine.skipDataMethods(true);

        sourceDocumentLine.skipEvents(true);

        sourceDocumentLine.skipTempTableForInsertRecordSet(true);


        insert_recordset sourceDocumentLine

        (

            ParentSourceDocumentLine,

            SourceDocumentHeader,

            AccountingStatus,

            ExchangeRateDate,

            SourceRelationType,

            TypeEnumName,

            TypeEnumValue,

            SourceImplementationRecId

        )

        select

            SourceDocumentLine,

            sourceDocumentHeader,

            AccountingStatus,

            ExchangeRateDate,

            SourceRelationType,

            TypeEnumName,

            TypeEnumValue

        from vendInvoiceInfoLine

            where vendInvoiceInfoLine.ParmId == _vendInvoiceInfoTable.ParmId

                && vendInvoiceInfoLine.TableRefId == _vendInvoiceInfoTable.TableRefId

        join RecId from _markUpTransTmpCopy

            where _markUpTransTmpCopy.TransTableId == vendInvoiceInfoLine.TableId

                && _markUpTransTmpCopy.TransRecId == vendInvoiceInfoLine.RecId

                && _markUpTransTmpCopy.SourceDocumentLine == 0;


        sourceDocumentLine.skipTempTableForInsertRecordSet(false);


        vendInvoiceInfoLine.clear();

        sourceDocumentLine.clear();


        update_recordset _markUpTransTmpCopy setting

            SourceDocumentLine = sourceDocumentLine.RecId

            where _markUpTransTmpCopy.SourceDocumentLine == 0

        join vendInvoiceInfoLine

            where vendInvoiceInfoLine.ParmId == _vendInvoiceInfoTable.ParmId

                && vendInvoiceInfoLine.TableRefId == _vendInvoiceInfoTable.TableRefId

                && vendInvoiceInfoLine.TableId == _markUpTransTmpCopy.TransTableId

                && vendInvoiceInfoLine.RecId == _markUpTransTmpCopy.TransRecId

        join sourceDocumentLine

            where sourceDocumentLine.SourceDocumentHeader == sourceDocumentHeader &&

                sourceDocumentLine.ParentSourceDocumentLine == vendInvoiceInfoLine.SourceDocumentLine &&

                sourceDocumentLine.SourceImplementationRecId == _markUpTransTmpCopy.RecId;


        SAN_GeneratePurchaseMarkupChargesHelper::insertMarkupTransRecordFromMarkupTransTmp(_markUpTransTmpCopy);


        //dispose buffers

        vendInvoiceInfoLine.dispose();

        _markUpTransTmpCopy.dispose();

        markupTransOtherInvoices.dispose();

        markUpTransMapping.dispose();

        sourceDocumentLine.dispose();

    }


    private static void insertMarkupTransRecordFromMarkupTransTmp(MarkupTransTmp _markUpTransTmpCopy)

    {

        SysDaInsertObject insertObj = SAN_GeneratePurchaseMarkupChargesHelper::buildMarkupTransInsertObject();

        SysDaQueryObject  queryObj  = SAN_GeneratePurchaseMarkupChargesHelper::buildMarkupTransTmpQueryObject(_markUpTransTmpCopy);

            

        SAN_GeneratePurchaseMarkupChargesHelper::insertRecords(queryObj, insertObj);

    }


    private static SysDaInsertObject buildMarkupTransInsertObject()

    {

        //insert_recordset markupTransDestination (

        //    BankLCImportChargeAllocation_SA, CalculatedAmount, CalculatedAmountMST_W, CurrencyCode, etc.)


        MarkupTrans markupTransDestination;


        markupTransDestination.skipEvents(true);

        markupTransDestination.skipDataMethods(true);

        markupTransDestination.skipTempTableForInsertRecordSet(true);


        SysDaInsertObject   markupTransInsertObject = new SysDaInsertObject(markupTransDestination);


        SAN_GeneratePurchaseMarkupChargesHelper::addMarkupTransFields(markupTransInsertObject.fields());


        return markupTransInsertObject;

    }


    private static SysDaQueryObject buildMarkupTransTmpQueryObject(MarkupTransTmp _markupTransTmpSource)

    {

        //select BankLCImportChargeAllocation_SA, CalculatedAmount, CalculatedAmountMST_W, CurrencyCode, etc. from markupTransTmpSource


        SysDaQueryObject markupTransTmpQueryObject = new SysDaQueryObject(_markupTransTmpSource);

        SAN_GeneratePurchaseMarkupChargesHelper::addMarkupTransFields(markupTransTmpQueryObject.projection());

        

        return markupTransTmpQueryObject;

    }


    private static void addMarkupTransFields(SysDaSelection _selectionObject)

    {

        _selectionObject

            .add(fieldStr(MarkupTrans, BankLCImportChargeAllocation_SA))

            .add(fieldStr(MarkupTrans, CalculatedAmount))

            .add(fieldStr(MarkupTrans, CalculatedAmountMST_W))

            .add(fieldStr(MarkupTrans, CurrencyCode))

            .add(fieldStr(MarkupTrans, CustomsAssessableValue_IN))

            .add(fieldStr(MarkupTrans, CustVendPosted_RU))

            .add(fieldStr(MarkupTrans, ExchRate_RU))

            .add(fieldStr(MarkupTrans, ExchRateSecond_RU))

            .add(fieldStr(MarkupTrans, FromAmount))

            .add(fieldStr(MarkupTrans, IsAutoCharge))

            .add(fieldStr(MarkupTrans, IsTieredCharge))

            .add(fieldStr(MarkupTrans, ItemPosted_RU))

            .add(fieldStr(MarkupTrans, Keep))

            .add(fieldStr(MarkupTrans, LineNum))

            .add(fieldStr(MarkupTrans, MarkupAllocateAfter_IN))

            .add(fieldStr(MarkupTrans, MarkupCategory))

            .add(fieldStr(MarkupTrans, MarkupClassification_BR))

            .add(fieldStr(MarkupTrans, MarkupCode))

            .add(fieldStr(MarkupTrans, MCRBrokerContractFee))

            .add(fieldStr(MarkupTrans, MCRCouponMarkup))

            .add(fieldStr(MarkupTrans, MCRInstallmentEligible))

            .add(fieldStr(MarkupTrans, MCRMarkupTransCreatedBy))

            .add(fieldStr(MarkupTrans, MCRMiscChargeOverride))

            .add(fieldStr(MarkupTrans, MCROriginalMiscChargeValue))

            .add(fieldStr(MarkupTrans, MCRReasonCode))

            .add(fieldStr(MarkupTrans, MCRRetailInfoCodeId))

            .add(fieldStr(MarkupTrans, MCRSavedRecId))

            .add(fieldStr(MarkupTrans, MCRSavedTableId))

            .add(fieldStr(MarkupTrans, ModuleCategory))

            .add(fieldStr(MarkupTrans, ModuleType))

            .add(fieldStr(MarkupTrans, NotionalCharges_IN))

            .add(fieldStr(MarkupTrans, NotionalPct_IN))

            .add(fieldStr(MarkupTrans, TaxAmount))

            .add(fieldStr(MarkupTrans, TaxAmountExcise_RU))

            .add(fieldStr(MarkupTrans, TaxAmountExciseMST_RU))

            .add(fieldStr(MarkupTrans, TaxAmountMst_W))

            .add(fieldStr(MarkupTrans, TaxAmountVAT_RU))

            .add(fieldStr(MarkupTrans, TaxAmountVATMST_RU))

            .add(fieldStr(MarkupTrans, TaxAutoGenerated))

            .add(fieldStr(MarkupTrans, TaxGroup))

            .add(fieldStr(MarkupTrans, TaxItemGroup))

            .add(fieldStr(MarkupTrans, TaxValueVAT_RU))

            .add(fieldStr(MarkupTrans, TaxVATType_RU))

            .add(fieldStr(MarkupTrans, TaxWriteCode))

            .add(fieldStr(MarkupTrans, ToAmount))

            .add(fieldStr(MarkupTrans, Txt))

            .add(fieldStr(MarkupTrans, Value))

            .add(fieldStr(MarkupTrans, VATDocumentType_RU))

            .add(fieldStr(MarkupTrans, SATProductCode_MX))

            .add(fieldStr(MarkupTrans, SATUnitCode_MX))

            .add(fieldStr(MarkupTrans, WithholdingTypeCode_MX))

            .add(fieldStr(MarkupTrans, MarkupAutoTableRecId))

            .add(fieldStr(MarkupTrans, RetailShippingPromotionDiscount))

            .add(fieldStr(MarkupTrans, IsAdvancedLineProrated))

            .add(fieldStr(MarkupTrans, IsOverriddenProratedLine))

            .add(fieldStr(MarkupTrans, MarkupAutoLineRecId))

            .add(fieldStr(MarkupTrans, IsOverriddenLine))

            .add(fieldStr(MarkupTrans, PreviousValue))

            .add(fieldStr(MarkupTrans, OverrideSalesTax))

            .add(fieldStr(MarkupTrans, TransTableId))

            .add(fieldStr(MarkupTrans, TransRecId))

            .add(fieldStr(MarkupTrans, OrigTableId))

            .add(fieldStr(MarkupTrans, OrigRecId))

            .add(fieldStr(MarkupTrans, SpecificUnitSymbol))

            .add(fieldStr(MarkupTrans, SourceDocumentLine));


        if (LedgerParameters::find().EnableWHTOnCharges == NoYes::Yes)

        {

            _selectionObject

                .add(fieldStr(MarkupTrans, TaxWithholdGroup))

                .add(fieldStr(MarkupTrans, TaxWithholdItemGroup));

        }

    }


    private static void insertRecords(SysDaQueryObject _queryObject, SysDaInsertObject _insertObject)

    {

        _insertObject.query(_queryObject);

        SysDaInsertStatement insertStatement = new SysDaInsertStatement();


        insertStatement.executeQuery(_insertObject);

    }


}

Thursday, October 10, 2024

Using SysOperationSandbox::callStaticMethod Sample in D365FO X++

 SysOperationSandbox::callStaticMethod(classnum(Classnum(<Class name>)), staticMethodStr(<Class name>, <Class static method name>), [<Parm1>, <Parm2>,<Parm3>], "<operation completion Message>");


 public static void updateOpr(container _callerParams)

 {

     if (conlen(_callerParams) != 3)

     {

         throw error("");

     }

     

     Anytype parm1 = conPeek(_callerParams, 1);

     Anytype parm2 = conPeek(_callerParams, 2);

     Anytype parm3 = conPeek(_callerParams, 3);        

        //Business Logic

 }

Export label custom content

 GRID => Properties "Export Label" => "SalesReportMexico" To get download file with custom naming.