Friday, December 1, 2023

Initializes form controls at runtime using X++ D365fo

/// <summary>
    /// Initializes LATAM form controls.
    /// </summary>
    /// <param name="_sender">The form run.</param>
    /// <param name="_args">The form event args.</param>
    [FormEventHandler(formStr(SalesEditLines), FormEventType::Initialized), SuppressBPWarning('BPParameterNotUsed', 'False positive')]
    public static void SalesEditLines_OnInitialized(xFormRun _sender, FormEventArgs _args)
    {
        if (!FeatureStateProvider::IsFeatureEnabled(LTMGlobalizationFeature::instance()))
        {
            return;
        }

        FormRun formRun = _sender;
        LTMSalesEditLines ltmSalesEditLines = formRun.parmLTMSalesEditLines();
        Struct controlsInv = new Struct();
        Struct controlsPS = new Struct();
        DocumentStatus documentStatus = formRun.args().caller().documentStatus();
        FormTabPageControl LTMTab = formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMTab)));

        // Dummies
        FormStringControl LTMPSBankGroupId =  LTMTab.addControl(FormControlType::String, 'LTMPSBankGroupId');
        FormComboBoxControl LTMPSCPDSource = LTMTab.addControl(FormControlType::ComboBox, 'LTMPSCPDSource');
        FormStringControl LTMPSControlCode =  LTMTab.addControl(FormControlType::String, 'LTMPSControlCode');
        FormStringControl LTMPSBeneficiary =  LTMTab.addControl(FormControlType::String, 'LTMPSBeneficiary');
        FormStringControl LTMPSHolderAccountNum =  LTMTab.addControl(FormControlType::String, 'LTMPSHolderAccountNum');
        FormRealControl LTMPSWithholdingBaseMST = LTMTab.addControl(FormControlType::Real, 'LTMPSWithholdingBaseMST');
        FormRealControl LTMPSWithholdAccruedAmountMST = LTMTab.addControl(FormControlType::Real, 'LTMPSWithholdAccruedAmountMST');
        FormRealControl LTMPSWithholdAccruedBaseMST = LTMTab.addControl(FormControlType::Real, 'LTMPSWithholdAccruedBaseMST');
        FormRealControl LTMPSAmountMST = LTMTab.addControl(FormControlType::Real, 'LTMPSAmountMST');
        FormRealControl LTMPSWithholdingEffectiveRate = LTMTab.addControl(FormControlType::Real, 'LTMPSWithholdingEffectiveRate');

        FormStringControl LTMInvBankGroupId =  LTMTab.addControl(FormControlType::String, 'LTMInvBankGroupId');
        FormComboBoxControl LTMInvCPDSource = LTMTab.addControl(FormControlType::ComboBox, 'LTMInvCPDSource');
        FormStringControl LTMInvControlCode =  LTMTab.addControl(FormControlType::String, 'LTMInvControlCode');
        FormStringControl LTMInvBeneficiary =  LTMTab.addControl(FormControlType::String, 'LTMInvBeneficiary');
        FormStringControl LTMInvHolderAccountNum =  LTMTab.addControl(FormControlType::String, 'LTMInvHolderAccountNum');
        FormRealControl LTMInvWithholdingBaseMST = LTMTab.addControl(FormControlType::Real, 'LTMInvWithholdingBaseMST');
        FormRealControl LTMInvWithholdAccruedAmountMST = LTMTab.addControl(FormControlType::Real, 'LTMInvWithholdAccruedAmountMST');
        FormRealControl LTMInvWithholdAccruedBaseMST = LTMTab.addControl(FormControlType::Real, 'LTMInvWithholdAccruedBaseMST');
        FormRealControl LTMInvAmountMST = LTMTab.addControl(FormControlType::Real, 'LTMInvAmountMST');
        FormRealControl LTMInvWithholdingEffectiveRate = LTMTab.addControl(FormControlType::Real, 'LTMInvWithholdingEffectiveRate');

        LTMPSBankGroupId.visible(false);
        LTMPSCPDSource.visible(false);
        LTMPSControlCode.visible(false);
        LTMPSBeneficiary.visible(false);
        LTMPSHolderAccountNum.visible(false);
        LTMPSWithholdingBaseMST.visible(false);
        LTMPSWithholdAccruedAmountMST.visible(false);
        LTMPSWithholdAccruedBaseMST.visible(false);
        LTMPSAmountMST.visible(false);
        LTMPSWithholdingEffectiveRate.visible(false);

        LTMInvBankGroupId.visible(false);
        LTMInvCPDSource.visible(false);
        LTMInvControlCode.visible(false);
        LTMInvBeneficiary.visible(false);
        LTMInvHolderAccountNum.visible(false);
        LTMInvWithholdingBaseMST.visible(false);
        LTMInvWithholdAccruedAmountMST.visible(false);
        LTMInvWithholdAccruedBaseMST.visible(false);
        LTMInvAmountMST.visible(false);
        LTMInvWithholdingEffectiveRate.visible(false);
       
        ltmSalesEditLines.parmForm(formRun.form());
        ltmSalesEditLines.parmTabLTM(formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMTab))));
        ltmSalesEditLines.parmSelectedTableAux(0);
        ltmSalesEditLines.parmDocumentStatus(documentStatus);
        ltmSalesEditLines.parmProforma(formRun.args().caller().proforma());
        ltmSalesEditLines.parmCheckLTM(formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPrintFormLetter))));
        ltmSalesEditLines.parmPrimaryDS(formRun.dataSource(formDataSourceStr(SalesEditLines, SalesParmTable)));
        ltmSalesEditLines.parmExtendDS(formRun.dataSource(formDataSourceStr(SalesEditLines, LTMSalesParmTableJour)));
        ltmSalesEditLines.parmExtendDS2(formRun.dataSource(formDataSourceStr(SalesEditLines, LTMSalesParmTablePS)));
        ltmSalesEditLines.parmGroupJour(formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvoiceGrp))));
        ltmSalesEditLines.parmGroupPS(formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPackingSlipGrp))));
        
        // Packing Slip
        controlsPS.add(LTMTransBasicConst::LTMDocumentClassificationId, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSVoucherClassId))));
        controlsPS.add(LTMTransBasicConst::LTMSalesPointId, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSSalesPointId))));
        controlsPS.add(LTMTransBasicConst::LTMSalesPointPrefix, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSSalesPointPrefix))));
        controlsPS.add(LTMTransBasicConst::LTMDocumentNum, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSDocumentNum))));
        controlsPS.add(LTMTransBasicConst::LTMCompleteDocumentNum, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSCompleteDocumentNum))));
        controlsPS.add(LTMTransBasicConst::LTMDocumentDate, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSDocumentDate))));
        controlsPS.add(LTMTransBasicConst::LTMCAICAEDueDate, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSCAICAEDueDate))));
        controlsPS.add(LTMTransBasicConst::LTMDueDate, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSDueDate))));
        controlsPS.add(LTMTransBasicConst::LTMCAICAE, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSCAICAE))));
        controlsPS.add(LTMTransBasicConst::LTMCountryDocTypeId, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSCountryDocTypeId))));
        controlsPS.add(LTMTransBasicConst::LTMCountryDocNum, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSCountryDocNum))));
        controlsPS.add(LTMTransBasicConst::LTMBussinessName, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSName))));
        controlsPS.add(LTMTransBasicConst::LTMConcept1, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSConcept1))));
        controlsPS.add(LTMTransBasicConst::LTMConcept2, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSConcept2))));
        controlsPS.add(LTMTransBasicConst::LTMConcept3, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSConcept3))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList01, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField01))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList02, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField02))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList03, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField03))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList04, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField04))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList05, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField05))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList06, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField06))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList07, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField07))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList08, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField08))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList09, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField09))));
        controlsPS.add(LTMTransBasicConst::LTMFieldList10, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSListField10))));
        controlsPS.add(LTMTransBasicConst::CountryRegionId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSCountryRegionId))));
        controlsPS.add(LTMTransBasicConst::StateId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSStateId))));
        controlsPS.add(LTMTransBasicConst::LTMStateDocTypeId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSStateDocTypeId))));
        controlsPS.add(LTMTransBasicConst::LTMStateDocNum,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSStateDocNum))));
        controlsPS.add(LTMTransBasicConst::LTMTaxPayerTypeId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMPSTaxPayerTypeId))));

        // Dummy fields
        controlsPS.add(LTMTransBasicConst::BankGroupId,LTMPSBankGroupId);
        controlsPS.add(LTMTransBasicConst::LTMCPDSource,LTMPSCPDSource);
        controlsPS.add(LTMTransBasicConst::LTMControlCode,LTMPSControlCode);
        controlsPS.add(LTMTransBasicConst::LTMBeneficiary,LTMPSBeneficiary);
        controlsPS.add(LTMTransBasicConst::LTMHolderAccountNum,LTMPSHolderAccountNum);
        controlsPS.add(LTMTransBasicConst::LTMWithholdingBaseMST,LTMPSWithholdingBaseMST);
        controlsPS.add(LTMTransBasicConst::LTMWithholdAccruedAmountMST,LTMPSWithholdAccruedAmountMST);
        controlsPS.add(LTMTransBasicConst::LTMWithholdAccruedBaseMST,LTMPSWithholdAccruedBaseMST);
        controlsPS.add(LTMTransBasicConst::AmountMST,LTMPSAmountMST);
        controlsPS.add(LTMTransBasicConst::LTMWithholdingEffectiveRate,LTMPSWithholdingEffectiveRate);
        
        // Invoice
        controlsInv.add(LTMTransBasicConst::LTMDocumentClassificationId, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvVoucherClassId))));
        controlsInv.add(LTMTransBasicConst::LTMSalesPointId, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvSalesPointId))));
        controlsInv.add(LTMTransBasicConst::LTMSalesPointPrefix, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvSalesPointPrefix))));
        controlsInv.add(LTMTransBasicConst::LTMDocumentNum, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvDocumentNum))));
        controlsInv.add(LTMTransBasicConst::LTMCompleteDocumentNum, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvCompleteDocumentNum))));
        controlsInv.add(LTMTransBasicConst::LTMDocumentDate, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvDocumentDate))));
        controlsInv.add(LTMTransBasicConst::LTMCAICAEDueDate, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvCAICAEDueDate))));
        controlsInv.add(LTMTransBasicConst::LTMDueDate, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvDueDate))));
        controlsInv.add(LTMTransBasicConst::LTMCAICAE, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvCAICAE))));
        controlsInv.add(LTMTransBasicConst::LTMControlCode, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMControlCode))));
        controlsInv.add(LTMTransBasicConst::LTMCountryDocTypeId, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvCountryDocTypeId))));
        controlsInv.add(LTMTransBasicConst::LTMCountryDocNum, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvCountryDocNum))));
        controlsInv.add(LTMTransBasicConst::LTMBussinessName, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvName))));
        controlsInv.add(LTMTransBasicConst::LTMConcept1, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvConcept1))));
        controlsInv.add(LTMTransBasicConst::LTMConcept2, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvConcept2))));
        controlsInv.add(LTMTransBasicConst::LTMConcept3, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvConcept3))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList01, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField01))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList02, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField02))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList03, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField03))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList04, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField04))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList05, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField05))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList06, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField06))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList07, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField07))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList08, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField08))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList09, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField09))));
        controlsInv.add(LTMTransBasicConst::LTMFieldList10, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvListField10))));
        controlsInv.add(LTMTransBasicConst::LTMInvEnablePS, formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvEnablePS))));
        controlsInv.add(LTMTransBasicConst::CountryRegionId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvCountryRegionId))));
        controlsInv.add(LTMTransBasicConst::StateId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvStateId))));
        controlsInv.add(LTMTransBasicConst::LTMStateDocTypeId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvStateDocTypeId))));
        controlsInv.add(LTMTransBasicConst::LTMStateDocNum,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvStateDocNum))));
        controlsInv.add(LTMTransBasicConst::LTMTaxPayerTypeId,formRun.control(formRun.controlId(formControlStr(SalesEditLines, LTMInvTaxPayerTypeId))));

        // Dummy fields
        controlsInv.add(LTMTransBasicConst::BankGroupId,LTMInvBankGroupId);
        controlsInv.add(LTMTransBasicConst::LTMCPDSource,LTMInvCPDSource);
        controlsInv.add(LTMTransBasicConst::LTMControlCode,LTMInvControlCode);
        controlsInv.add(LTMTransBasicConst::LTMBeneficiary,LTMInvBeneficiary);
        controlsInv.add(LTMTransBasicConst::LTMHolderAccountNum,LTMInvHolderAccountNum);
        controlsInv.add(LTMTransBasicConst::LTMWithholdingBaseMST,LTMInvWithholdingBaseMST);
        controlsInv.add(LTMTransBasicConst::LTMWithholdAccruedAmountMST,LTMInvWithholdAccruedAmountMST);
        controlsInv.add(LTMTransBasicConst::LTMWithholdAccruedBaseMST,LTMInvWithholdAccruedBaseMST);
        controlsInv.add(LTMTransBasicConst::AmountMST,LTMInvAmountMST);
        controlsInv.add(LTMTransBasicConst::LTMWithholdingEffectiveRate,LTMInvWithholdingEffectiveRate);

        ltmSalesEditLines.parmControlsSalesEditLines(controlsPS, controlsInv);
        ltmSalesEditLines.init();
        ltmSalesEditLines.parmLTMReArrangeNow(false);
    }

Read CSV file using X++

class RGReadSample
{       
    ///

    /// Runs the class with the specified arguments.
    ///

    /// The specified arguments.
    public static void main(Args _args)
    {       
        AsciiStreamIo                                   file;
        Array                                           fileLines;
        FileUploadTemporaryStorageResult                fileUpload;
        fileUpload = File::GetFileFromUser() as FileUploadTemporaryStorageResult;
        file = AsciiStreamIo::constructForRead(fileUpload.openResult());
        if (file)
        {
            if (file.status())
            {
                throw error("@SYS52680");
            }
            file.inFieldDelimiter(',');
            file.inRecordDelimiter('\r\n');
        }
        container record;
        while (!file.status())
        {
            record = file.read();
            if (conLen(record))
            {
                info(strFmt("%1 - %2",conPeek(record,1),conPeek(record,2)));
            }
        }
        info("done");
    }
}

Extract files from zip file and upload using X++

 /// <summary>
    /// Extract files from zip file and upload.
    /// </summary>
    /// <param name = "_uploadFileURL">DownLoad of the zip file.</param>
    /// <param name = "_fileSuffixes>List of file suffixes which serves as filter.</param>
    /// <returns>List of file IDs of the unzipped files which meet filter in file suffix list; returns all files if the filter is empty.</returns>
    public static List getUnzippedFiles(SharedServiceUnitURL _uploadFileURL, container _fileSuffixes)
    {
        #File

        System.IO.Compression.ZipArchive zipArchive =
            new System.IO.Compression.ZipArchive(File::UseFileFromURL(_uploadFileURL), System.IO.Compression.ZipArchiveMode::Read);

        CLRObject archiveEntries =  zipArchive.get_Entries();
        int length = archiveEntries.get_Count();

        List uploadUrlList = new List(types::Container);
        container consUnzippedFile;
        int i;

        for (i = 0; i < length; i++)
        {
            System.IO.Compression.ZipArchiveEntry item = archiveEntries.get_Item(i);
            List fileNameComponents = strSplit(item.Name, #FileExtensionDelimiter);
            ListIterator iterator = new ListIterator(fileNameComponents);
            str fileSuffix;
            while (iterator.more())
            {
                fileSuffix = iterator.value();
                iterator.next();
            }

            if (conLen(_fileSuffixes) == 0 || conFind(_fileSuffixes, fileSuffix) > 0)
            {
                using(System.IO.MemoryStream stream = new System.IO.MemoryStream())
                {
                    item.Open().CopyTo(stream);
                    str fileID = BankStatementImportUtils::sendFileToTempStore(stream, item.Name).getFileId();
                    consUnzippedFile = [fileID, item.Name];
                    uploadUrlList.addEnd(consUnzippedFile);
                }
            }
        }

        return uploadUrlList;
    }

Sysoperation framework with file upload and UI builder D365FO

class ImportSveaFileService_Custom extends SysOperationServiceBase
{
    private Map companyLedgerJournalTableMap;
    public void run(ImportSveaFileContract_Custom _contract)
    {
        if (_contract.parmStorageResult() != conNull())
        {
            FileUploadTemporaryStorageResult fileUploadResult = new FileUploadTemporaryStorageResult();

            fileUploadResult.unpack(_contract.parmStorageResult());

            if (fileUploadResult != null)
            {
                try
                {
                    System.IO.Stream fileStream = File::UseFileFromURL(fileUploadResult.getDownloadUrl());

                    XmlDocument doc;
                    XmlNodeList data;
                    XmlElement nodeTable;
                    XmlElement nodeId;
                    XMLParseError xmlError;
                    doc = XmlDocument::newFromStream(fileStream);

                    int lineNum = 0;
                    real totalamountHeader, totalamountTrans = 0;
                    real totalDiscfee, totalAdmfee;
                    CurrencyCode currencyCode;

                    // Verify XML Document Structure
                    xmlError  = doc.parseError();
                    if(xmlError && xmlError.errorCode() != 0)
                    {
                        throw error(strFmt("XML Error: %1", xmlError.reason()));
                    }

                    BankAccountTable bankAccountTable = BankAccountTable::find(_contract.parmBankAccount());
                    LedgerJournalTable ledgerJournalTable = LedgerJournalTable::find(_contract.parmJournalId());
                    data = doc.selectNodes('//'+"header");
                    nodeTable = data.nextNode();
                    while (nodeTable)
                    {
                        nodeId = nodeTable.selectSingleNode("totalamount");
                        totalamountHeader = str2Num(nodeId.text());
                        nodeId = nodeTable.selectSingleNode("batchcurrency");
                        currencyCode = nodeId.text();
                      
                        nodeTable = data.nextNode();
                    }

                    data = doc.selectNodes('//'+"transaction");
                    nodeTable = data.nextNode();
                    //LedgerJournalTrans custLedgerJournalTrans;
                    //RecordInsertList   recordInsertListLedgerJournalTrans = new RecordInsertList(tableNum(LedgerJournalTrans));
                   
                    while (nodeTable)
                    {
                        ttsbegin;
                        real  discfee, admfee, invoiceamount;
                        LedgerJournalTrans custLedgerJournalTrans;

                        custLedgerJournalTrans.JournalNum   = ledgerJournalTable.JournalNum;
                        custLedgerJournalTrans.LineNum      = lineNum;

                        lineNum++;

                        Voucher     voucher;
                        NumberSeq   numberSeq;
                        numberSeq   = NumberSeq::newGetVoucherFromId(ledgerJournalTable.NumberSequenceTable);
                        voucher     = numberSeq.voucher();
                        custLedgerJournalTrans.Voucher          = voucher;

                        custLedgerJournalTrans.CurrencyCode     = currencyCode;
                        custLedgerJournalTrans.AccountType      = LedgerJournalACType::Cust;
                        custLedgerJournalTrans.TransactionType  = LedgerTransType::Payment;

                        nodeId = nodeTable.selectSingleNode("invoicedate");
                        custLedgerJournalTrans.TransDate = str2Date(nodeId.text(),321);
                     
                        nodeId = nodeTable.selectSingleNode("customernumber");
                        CustAccount custAccountNum = CustTable::findRecId(str2recId(nodeId.text())).AccountNum;
                        custLedgerJournalTrans.parmAccount(custAccountNum, LedgerJournalACType::Cust);
                    
                        CustTable custTable = CustTable::find(custLedgerJournalTrans.parmAccount());

                        if (custTable)
                        {
                            custLedgerJournalTrans.DefaultDimension = custTable.DefaultDimension;
                            custLedgerJournalTrans.Payment = custTable.PaymTermId;
                        }
             
                        nodeId = nodeTable.selectSingleNode("invoiceid");
                        custLedgerJournalTrans.MarkedInvoice        = nodeId.text();
                        custLedgerJournalTrans.MarkedInvoiceCompany = curExt();

                        nodeId = nodeTable.selectSingleNode("invoiceamount");
                        invoiceamount = str2Num(nodeId.text());
                        custLedgerJournalTrans.amountCur2DebCred(invoiceamount * -1);

                        custLedgerJournalTrans.OffsetAccountType            = LedgerJournalACType::Bank;
                        custLedgerJournalTrans.OffsetLedgerDimension        = bankAccountTable.LedgerDimension;
                        custLedgerJournalTrans.Triangulation                = Currency::triangulation(custLedgerJournalTrans.CurrencyCode, custLedgerJournalTrans.TransDate);
                        custLedgerJournalTrans.ExchRate                     = ExchangeRateHelper::exchRate(custLedgerJournalTrans.CurrencyCode, custLedgerJournalTrans.TransDate);
                        custLedgerJournalTrans.ExchRateSecond               = ExchangeRateHelper::exchRateSecond(custLedgerJournalTrans.CurrencyCode, custLedgerJournalTrans.TransDate);
                        custLedgerJournalTrans.PostingProfile               = CustParameters::find().PostingProfile;
                        custLedgerJournalTrans.BankCentralBankPurposeCode   = custTable.BankCentralBankPurposeCode;
                        custLedgerJournalTrans.BankCentralBankPurposeText   = custTable.BankCentralBankPurposeText;
                        custLedgerJournalTrans.Txt                          = this.determineTransactionText(LedgerTransTxt::CustVendNetVendor, custLedgerJournalTrans);
                        custLedgerJournalTrans.OffsetTxt                    = this.determineTransactionText(LedgerTransTxt::CustVendNetLedger, custLedgerJournalTrans);

                        nodeId  = nodeTable.selectSingleNode("discfee");
                        discfee = str2Num(nodeId.text());

                        nodeId  = nodeTable.selectSingleNode("admfee");
                        admfee   = str2Num(nodeId.text());

                        CustInvoiceJour CustInvoiceJour;
                       
                        select firstonly custInvoiceJour
                            where custInvoiceJour.InvoiceId == custLedgerJournalTrans.MarkedInvoice &&
                                    custInvoiceJour.InvoiceDate == custLedgerJournalTrans.TransDate &&
                                        custInvoiceJour.InvoiceAccount == custTable.AccountNum;

                        if (invoiceamount != custInvoiceJour.InvoiceAmount)
                        {
                            warning(strFmt("Invoice amount mismatch on %1", custInvoiceJour.InvoiceId));
                        }

                        totalamountTrans += invoiceamount;
                        totalDiscfee     += discfee;
                        totalAdmfee      += admfee;

                        nodeTable = data.nextNode();

                        custLedgerJournalTrans.insert();
                        
                        LedgerJournalEngine_CustPayment::updateMarkedInvoiceSpecTrans(custLedgerJournalTrans);
                        ttscommit;
                        //recordInsertListLedgerJournalTrans.add(custLedgerJournalTrans);
                    }
                   // recordInsertListLedgerJournalTrans.insertDatabase();
                    info(strFmt("Total amount from file: %1 - total from journal: %2 -Total discfee: %3 – Total admfee: %4",totalamountHeader, totalamountTrans, totalDiscfee, totalAdmfee));
                }
                catch (Exception::Error)
                {
                    error("@RET433");
                }
            }
        }
    }

    private TransactionTextLarge determineTransactionText(
        LedgerTransTxt _ledgerTransTxt,
        LedgerJournalTrans _ledgerJournalTrans)
    {
        TransactionTxt transactionTxt = TransactionTxt::construct();

        transactionTxt.setType(_ledgerTransTxt);
        transactionTxt.setVoucher(_ledgerJournalTrans.Voucher);
        transactionTxt.setDate(_ledgerJournalTrans.TransDate);
        transactionTxt.setKey1(_ledgerJournalTrans.parmAccount());
        transactionTxt.setFormLetter(_ledgerJournalTrans.Voucher);

        return transactionTxt.txt();
    }

}
===========
class ImportSveaFileUIBuilder_Custom extends SysOperationAutomaticUIBuilder
{
    private str                 availableTypes = ".xml";
    private const str           OkButtonName = 'CommandButton';
    private const str           FileUploadName = 'FileUpload';

    ImportSveaFileContract_Custom   contract;
    /// <summary>
    /// Overriden the <c>postBuild</c> method to add a <c>FileUpload</c> control
    /// </summary>
    public void postBuild()
    {
        DialogGroup      dialogGroup;
        FormBuildControl formBuildControl;
        FileUploadBuild  dialogFileUpload;

        super();

        contract = this.dataContractObject();
        
        dialogGroup = dialog.addGroup("File path");
        formBuildControl = dialog.formBuildDesign().control(dialogGroup.name());
       
        dialogFileUpload = formBuildControl.addControlEx(classstr(FileUpload), FileUploadName);
        dialogFileUpload.style(FileUploadStyle::MinimalWithFilename);
        dialogFileUpload.baseFileUploadStrategyClassName(classstr(FileUploadTemporaryStorageStrategy));
        dialogFileUpload.fileTypesAccepted(availableTypes);
        dialogFileUpload.fileNameLabel("@SYS308842");
    }

    /// <summary>
    /// Subscribes events to the dialog form
    /// </summary>
    /// <param name = "_formRun">The instance of the dialog form</param>
    private void dialogEventsSubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(FileUploadName));
        fileUpload.notifyUploadCompleted += eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted += eventhandler(this.uploadStarted);
        _formRun.onClosing += eventhandler(this.dialogClosing);
    }

    /// <summary>
    /// Executes logic for unsubscribing the registered events on the form
    /// </summary>
    /// <param name = "sender"></param>
    /// <param name = "e"></param>
    [SuppressBPWarningAttribute('BPParameterNotUsed', 'This is event parameter not required to use')]
    private void dialogClosing(xFormRun sender, FormEventArgs e)
    {
        this.dialogEventsUnsubscribe(sender as FormRun);
    }

    /// <summary>
    /// Unsubscribes events from the dialog form
    /// </summary>
    /// <param name = "_formRun">The instance of the dialog form</param>
    private void dialogEventsUnsubscribe(FormRun _formRun)
    {
        FileUpload fileUpload = _formRun.control(_formRun.controlId(FileUploadName));
        fileUpload.notifyUploadCompleted -= eventhandler(this.uploadCompleted);
        fileUpload.notifyUploadAttemptStarted -= eventhandler(this.uploadStarted);
        _formRun.onClosing -= eventhandler(this.dialogClosing);
    }

    /// <summary>
    /// Executes additional logic once the upload of the file is completed
    /// </summary>
    protected void uploadCompleted()
    {
        var formRun = this.dialog().dialogForm().formRun();
        FileUpload fileUpload = formRun.control(formRun.controlId(FileUploadName));
        FileUploadTemporaryStorageResult uploadResult = fileUpload.getFileUploadResult();

        if (uploadResult != null && uploadResult.getUploadStatus())
        {
            contract.parmStorageResult(uploadResult.pack());
        }

        this.setDialogOkButtonEnabled(formRun, true);
    }

    /// <summary>
    /// Additional logic which is executed once the upload of the file has started
    /// </summary>
    private void uploadStarted()
    {
        var formRun = this.dialog().dialogForm().formRun();
        this.setDialogOkButtonEnabled(formRun, false);
    }

    /// <summary>
    /// Enables/Disables the OK button of the dialog
    /// </summary>
    /// <param name = "_formRun">The instance of the dialog form</param>
    /// <param name = "_isEnabled">Should the OK button be enabled?</param>
    protected void setDialogOkButtonEnabled(FormRun _formRun, boolean _isEnabled)
    {
        FormControl okButtonControl = _formRun.control(_formRun.controlId(OkButtonName));
        if (okButtonControl)
        {
            okButtonControl.enabled(_isEnabled);
        }
    }

    /// <summary>
    /// Override of the <c>postRun</c> method in order to add events subscriptions
    /// </summary>
    public void postRun()
    {
        super();

        FormRun formRun = this.dialog().dialogForm().formRun();
        this.dialogEventsSubscribe(formRun);

        this.setDialogOkButtonEnabled(formRun, false);
    }

}
===
class ImportSveaFileController_Custom extends SysOperationServiceController
{
    /// <summary>
    ///     Constructs an instance
    /// </summary>
    /// <returns>an instance of class</returns>
    public static ImportSveaFileController_Custom construct(Args _args)
    {
        ImportSveaFileController_Custom controller = new ImportSveaFileController_Custom(classstr(ImportSveaFileService_Custom),
                                                                                           methodstr(ImportSveaFileService_Custom, run),
                                                                                           SysOperationExecutionMode::Synchronous);
        controller.parmArgs(_args);
        controller.initializeContract(controller);

        return controller;
    }

    /// <summary>
    /// Initializes the contract parameters.
    /// </summary>
    /// <param name = "_controller">An instance of the <c>CAMPeriodCalculationController</c> whose contract to initialize.</param>
    protected void initializeContract(ImportSveaFileController_Custom _controller)
    {
        LedgerJournalTable ledgerJournalTable = this.parmArgs().record();

        if (ledgerJournalTable)
        {
            ImportSveaFileContract_Custom contract = _controller.getDataContractObject() as ImportSveaFileContract_Custom;

            if (contract)
            {
                contract.parmJournalId(ledgerJournalTable.JournalNum);
            }
        }
    }

    /// <summary>
    /// Instantiate controller.
    /// </summary>
    //protected void new()
    //{
    //    super(classStr(ImportSveaFileService_Custom),
    //    methodStr(ImportSveaFileService_Custom,run ));
    //    this.parmDialogCaption("Import Svea file into payment journal");
    //}

    /// <summary>
    /// Runs the class with the specified arguments.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        ImportSveaFileController_Custom::construct(_args).startOperation();
        //ImportSveaFileController_Custom controller = ImportSveaFileController_Custom::newFromArgs();
        //controller.parmExecutionMode(SysOperationExecutionMode::Synchronous);
        //controller.startOperation();
    }

    /// <summary>
    /// Instantiate and initialize controller class.
    /// </summary>
    /// <returns>
    /// returns controller class.
    /// </returns>
    //public static ImportSveaFileController_Custom newFromArgs()
    //{
    //    ImportSveaFileController_Custom controller = ImportSveaFileController_Custom::construct();
    //    return controller;
    //}

}
====
[DataContractAttribute,
SysOperationContractProcessing(classStr(ImportSveaFileUIBuilder_Custom))]
class ImportSveaFileContract_Custom
{
    LedgerJournalId   journalId;
    CompanyBankAccountId bankAccount;
    container       storageResult;

    /// <summary>
    ///     Get/Set the email address
    /// </summary>
    /// <param name = "_emailAddress">email address</param>
    /// <returns>email address</returns>
    [DataMemberAttribute,
    SysOperationLabelAttribute(literalStr("Bank account")),
    SysOperationDisplayOrderAttribute('1')]
    public CompanyBankAccountId parmBankAccount(CompanyBankAccountId _bankAccount = bankAccount)
    {
        bankAccount = _bankAccount;

        return bankAccount;
    }

    /// <summary>
    ///     Get/Set the email address
    /// </summary>
    /// <param name = "_emailAddress">email address</param>
    /// <returns>email address</returns>
    [DataMemberAttribute,
    SysOperationLabelAttribute(literalStr("Journal num")),
    SysOperationDisplayOrderAttribute('3'),
        SysOperationControlVisibility(false)]
    public LedgerJournalId parmJournalId(LedgerJournalId _journalId = journalId)
    {
        journalId = _journalId;

        return journalId;
    }

    /// <summary>
    /// Parameter method which holds values of the packed variables from <c>FileUploadTemporaryStorageResult</c> class
    /// </summary>
    /// <param name = "_storageResult">Packed instance of <c>FileUploadTemporaryStorageResult</c> class</param>
    /// <returns>Container with packed values</returns>
    [DataMemberAttribute('StorageResult'),
        SysOperationDisplayOrderAttribute('2')]
    public container parmStorageResult(container _storageResult =  storageResult)
    {
        storageResult = _storageResult;
        return storageResult;
    }

}

Write IOStream to azure blob using X++

/// <summary>
///     Service class for export customer details to blob storage
///    /// </summary>
using BlobStorage = Microsoft.WindowsAzure.Storage;
using Microsoft.Dynamics.AX.Framework.FileManagement;
using System.IO;
class ExportCustomerDetailsToAzureBlobService extends SysOperationServiceBase
{
    QueryRun    queryRun;
    CustTable   custTable;
 
    /// <summary>
    ///     Export customer details to blob storage
    /// </summary>
    /// <param name = "_contract">contract class</param>
    public void run(ExportCustomerDetailsToAzureBlobContract _contract)
    {
        // create a new queryrun object
        queryRun = new queryRun(_contract.getQuery());
 
        CommaStreamIo       io = CommaStreamIo::constructForWrite();
        const str           connectionString = "DefaultEndpointsProtocol=https;AccountName=arorasamplestorageacc;AccountKey=qRAbReWrFS5a4pVg7fVBdACk0/q4AzpwM6YBT7LYT4oAapZjCr1Wc5bNB1Lia9oYZXO7R/M17okx+AStaDNKFg==;EndpointSuffix=core.windows.net";
        const str           containerName = "arorasamplecontainer";
 
        TransDate   curDate = DateTimeUtil::getToday(DateTimeUtil::getUserPreferredTimeZone());
 
        str         curYear = int2Str(year(curDate));
        str         curMth  = int2Str(mthOfYr(curDate));
 
        if (strLen(curMth) == 1)
        {
            curMth = '0'+curMth;
        }
 
        str         curDay = int2Str(dayOfMth(curDate));
 
        if (strLen(curDay) == 1)
        {
            curDay = '0'+curDay;
        }
 
        str         mergedDate = curYear+curMth+curDay;
 
        TimeOfDay  curTime = DateTimeUtil::getTimeNow(DateTimeUtil::getUserPreferredTimeZone());
 
        str         mergedTime = time2StrHMS(curTime);
        mergedTime = strRem(mergedTime, ':');
        mergedTime = strRem(mergedTime, ' ');
 
        if (strLen(mergedTime) == 5)
        {
            mergedTime = '0'+mergedTime;
        }
 
        str         mergedDateTime = mergedDate+mergedTime;
 
        str         fileName = strFmt('%1_%2.csv',curExt(), mergedDateTime);
        BlobStorage.CloudStorageAccount storageAccount = BlobStorage.CloudStorageAccount::Parse(connectionString);
        BlobStorage.Blob.CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
        BlobStorage.Blob.CloudBlobContainer blobContainer = blobClient.GetContainerReference(containerName);
        blobContainer.CreateIfNotExistsAsync();
        io.writeExp(['Data area', 'Org number' , 'Tax receipt number']);
        // loop all results from the query
        while(queryRun.next())
        {
            custTable = queryRun.get(tablenum(CustTable));
 
            DirOrganization organization = DirOrganization::find(custTable.Party);
 
            io.writeExp([custTable.DataAreaId, organization.OrgNumber, subStr(custTable.VATNum, 2, -3)]);
        }
        BlobStorage.Blob.CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(fileName);
        if(blockBlob && !blockBlob.Exists(null,null))
        {
            System.IO.Stream stream = iO.getStream();
            stream.Position = 0;
            System.IO.StreamReader reader = new System.IO.StreamReader(stream);
            str csvFileContent = reader.ReadToEnd();
            if(csvFileContent)
            {
                blockBlob.UploadText(csvFileContent,null,null,null,null);
                blockBlob.FetchAttributes(null,null,null);
                BlobStorage.Blob.BlobProperties blobProperties = blockBlob.Properties;
                if(blobProperties.Length != 0)
                {
                    info('File upload successful');
                }
            }
        }
        else
        {
            info('File already exits');
        }
    }
 
}

use AOTResource images as container X++

container image = ImageReference::constructForAotResource(resourceStr("RedStatus")).pack();

Send email X++

public static void sendEmail(str _fileName,
                                 str _subject,
                                 str _body,
                                 System.IO.MemoryStream _memoryStream,
                                 Email _fromEmail, 
                                 Email _toEmail)
    {
        SysMailerMessageBuilder mailer = new SysMailerMessageBuilder();
        try
        {
            mailer.setSubject(_subject);

            //mailer.setFrom(_fromEmail);

            mailer.setBody(_body);

            mailer.addTo(_toEmail);

            mailer.addAttachment(_memoryStream, _fileName);

            SysMailerFactory::sendNonInteractive(mailer.getMessage());

            Info("@SYS58551");
        }
        catch (Exception::CLRError)
        {
            System.Exception ex = ClrInterop::getLastException();
            if (ex != null)
            {
                ex = ex.get_InnerException();
                if (ex != null)
                {
                    error(ex.ToString());
                }
            }
        }
        catch (Exception::Error)
        {
            Error("@ErrorOccurredFailedSendEmail");
        }
    }

Tuesday, September 26, 2023

Generating 1D or 2D barcode in X++

Barcode barcode = BarcodeCode128::construct();
barcode.string(true, localInventDim.inventSerialId);
BarCodeString barCodeString = barcode.barcodeStr();
public str getBarcode(str _barCodeText)

  {

   BarcodeCode128 barcode;

   barcode = Barcode::construct(BarcodeType::Code128);

   barcode.string(true, _barCodeText);

   barcode.encode();

   return barcode.barcodeStr();

   }

Monday, September 25, 2023

Convert Json to XML C#

sing System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Xml.Linq;

namespace JSONStringConvert
{
    public class Utilities
    {
        public static string ConvertToXML(string json)
        {
            //if an empty string is passed, return empty string without conversion
            if (string.IsNullOrEmpty(json))
                return string.Empty;
            //if invalid json is passed, throw error.
            ValidateJSON(json);
            //Convert Json to XML
            XDocument xmlDoc = JsonConvert.DeserializeXNode(json);
            return xmlDoc.ToString();
        }
        public static void ValidateJSON(string json)
        {
            try
            {
                var jsonObject = JObject.Parse(json);
            }
            catch (Exception ex)
            {
                throw new InvalidCastException("Provided json is not valid.", ex);
            }
        }
    }
}

Gets the primary index of a table

// <summary>
    /// Gets the primary index of a table.
    /// </summary>
    /// <param name="_tableName">
    /// A table name.
    /// </param>
    /// <returns>
    /// Returns field id.
    /// </returns>
    public static Container getPrimaryIndex(TableName _tableName)
    {
        SysDictIndex        keyIndex;
        DictField           dictField;
        int                 fieldIndex;
        container           res, isMandatory;
        SysDictTable sysDictTable = new SysDictTable(tableName2id(_tableName));
        if(sysDictTable)
        {
            TableId tableId = sysDictTable.id();
            keyIndex = new SysDictIndex(tableId, sysDictTable.primaryIndex());
            if (keyIndex)
            {
                for (fieldIndex = 1; fieldIndex <= keyIndex.numberOfFields(); fieldIndex++)
                {

                    if (fieldId2name(tableId, keyIndex.field(fieldIndex)) != fieldStr(DMFDefinitionGroupExecution,ExecutionId) &&
                        fieldId2name(tableId, keyIndex.field(fieldIndex)) != fieldStr(DMFDefinitionGroupExecution,DefinitionGroup))
                    {
                        dictField = new DictField(tableId, keyIndex.field(fieldIndex));
                        res += dictField.id();
                        isMandatory += dictField.mandatory();
                    }
                }
            }
        }

        return [res, isMandatory];
    }

Find all the tables in Ax that have no indexes

SQLDictionary   dict;
    DictTable       dictTable;

    ;
    while select dict
    where dict.fieldId == 0 // only tablenames
    {
        dictTable = new DictTable(dict.tabId);
        if ( dictTable.indexCnt() == 0 && ! dictTable.isView() )
        {
            info(strfmt("Table %1 has no indexes", dictTable.name()));
        }
    }

Call insert or update for dataentity

Var enumerator = entityNames.getEnumerator();

while (enumerator.MoveNext())
{
	Microsoft.Dynamics.AX.Metadata.MetaModel.AxDataEntityView DataEntity = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetDataEntityView(enumerator.Current);
	//matching with publicname of the entity
	if(DataEntity.PublicEntityName == parentNodeName)
	{
		entityName  = DataEntity.Name;
		dictTable   = new SysDictTable(tableName2Id(entityName));
		dictDataEntity   = new DictDataEntity(tableName2Id(entityName));
		common           = dictDataEntity.makeRecord();
		break;
	}
}
ttsbegin;
dictDataEntity.callObject("Write", common);
ttscommit;

X++ code to get metadata of data entities

var entityNames = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetDataEntityViewNames();

Var enumerator = entityNames.getEnumerator();

while (enumerator.MoveNext())

{
	enumerator.MoveNext();

	Microsoft.Dynamics.AX.Metadata.MetaModel.AxDataEntityView DataEntity = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetDataEntityView(enumerator.Current);

   if (DataEntity)
   {         

		info(strFmt("Entity Name: %1 -- Entity Label; %2 -- Entity public collection Name: %3 -- Entity Public Name %4 -- Is Entity Public - %5--Is Entity Shared - %6",

		DataEntity.Name,
		SysLabel::labelId2String(DataEntity.Label),
		DataEntity.PublicCollectionName,
		DataEntity.PublicEntityName,
		DataEntity.IsPublic,
		DataEntity.PrimaryCompanyContext));
     }
}

Get D365Fo Host name

using Microsoft.Dynamics.ApplicationPlatform.Environment;
public str GetInfrastructureHost()
{
        IApplicationEnvironment env = EnvironmentFactory::GetApplicationEnvironment();
        str hostUrl = env.Infrastructure.HostUrl;
        
        // Trim https://
        hostUrl = subStr(hostUrl, 9, strLen(hostUrl) - 8);

        return subStr(hostUrl, 1, strFind(hostUrl, '.', 1, strLen(hostUrl)) - 1);
}

Thursday, August 10, 2023

Create Transfer order using X++

public void createTransferOrder(InventLocationId _inventLocationIdFrom,InventLocationId  _inventLocationIdTo, TransDate _deliveryDate)
    {
        inventTransferTable.clear();
        inventTransferTable.initValue();

        InventTransferId transferOrderId = InventTransferTable::numberSeq().num();
        inventTransferTable.TransferId = transferOrderId;

        inventTransferTable.InventLocationIdFrom = _inventLocationIdFrom;
        inventTransferTable.modifiedField(fieldNum(InventTransferTable, InventLocationIdFrom));
        inventTransferTable.InventLocationIdTo = _inventLocationIdTo;
        inventTransferTable.modifiedField(fieldNum(InventTransferTable, InventLocationIdTo));
        inventTransferTable.InventLocationIdTransit = InventLocation::find(inventTransferTable.InventLocationIdFrom).InventLocationIdTransit;
        inventTransferTable.DeliveryDateControlType = SalesDeliveryDateControlType::None;
        inventTransferTable.ShipDate = _deliveryDate;
        inventTransferTable.ReceiveDate = _deliveryDate;

        inventTransferTable.initFromAddress();
        inventTransferTable.initToAddress();
        inventTransferTable.AutoReservation = true;

        if (inventTransferTable.validateWrite())
        {
            inventTransferTable.insert();
        }
        else
        {
            throw error("@SCM:FailTransferOrder");
        }
    }

    
    /// <summary>
    /// Create transfer order lines
    /// </summary>
    /// <param name = "_currPurchLine">PurchLine table buffer</param>
    /// <param name = "_inventTransferTable">Transfer order header buffer</param>
    public void createTransferLine(PurchLine _currPurchLine, InventTransferTable _inventTransferTable)
    {
        InventTransferLine currInventTransferLine;
        
        currInventTransferLine.initValue();
        
        currInventTransferLine.ItemId		= _currPurchLine.ItemId;

        currInventTransferLine.initFromInventTable(InventTable::find(_currPurchLine.ItemId));
        currInventTransferLine.initFromInventTableModule(InventTableModule::find(currInventTransferLine.ItemId, ModuleInventPurchSales::Invent));
        currInventTransferLine.initFromInventTransferTable(_inventTransferTable, true);

        currInventTransferLine.inventdimid	= _currPurchLine.InventDimId;
        
        currInventTransferLine.QtyTransfer = _currPurchLine.QtyOrdered;
        currInventTransferLine.QtyRemainReceive = currInventTransferLine.QtyTransfer;
        currInventTransferLine.QtyRemainShip    = currInventTransferLine.QtyTransfer;

        currInventTransferLine.DeliveryDateControlType = SalesDeliveryDateControlType::None;

        TransDate shipdate = this.getShipDate(_currPurchLine);
       
        currInventTransferLine.ShipDate = shipdate;
        InventItemInventSetup inventItemInventSetup = InventItemInventSetup::find(currInventTransferLine.itemId, currInventTransferLine.inventDimId);

        if (inventItemInventSetup.LeadTime)
        {
            currInventTransferLine.ReceiveDate =  currInventTransferLine.ShipDate + inventItemInventSetup.LeadTime;
        }
        else
        {
            currInventTransferLine.modifiedField(fieldNum(InventTransferLine, ShipDate));
        }

        currInventTransferLine.LineNum = _currPurchLine.LineNumber;

        
        if (currInventTransferLine.validateWrite())
        {
            currInventTransferLine.insert();

            info(strFmt("@SCM:CreateTOfromSalesLine", currInventTransferLine.TransferId, currInventTransferLine.ItemId));
           
        }
        else
        {
            throw error(strFmt("@SCM:FailedToCreateTtransferLineFromSalesLine", currInventTransferLine.TransferId, currInventTransferLine.ItemId));
        }
    }

Select Min and Max dates from lines

/// <summary>
    ///  set date for inventtransfer header
    /// </summary>
    /// <param name = "_inventTransferTable">
    /// InventTransferTable buffer
    /// </param>
    /// <param name = "_purchId">
    /// Purchase order number
    /// </param>
    public void setDatesInventTransferTable(InventTransferTable _inventTransferTable, PurchIdBase _purchId)
    {
        InventTransferLine transferLine;

        _inventTransferTable.reread();
        _inventTransferTable.selectForUpdate(true);

        select minof(ShipDate), maxof(ReceiveDate) from transferLine
                                where transferLine.TransferId == _inventTransferTable.TransferId;

        _inventTransferTable.ShipDate = transferLine.ShipDate;
        _inventTransferTable.ReceiveDate =  transferLine.ReceiveDate;
        _inventTransferTable.PurchaseOrderId_DIS =  _purchId;

        _inventTransferTable.update();
    }

Retrieves the format for data regarding date and time in Date format - ISO 8601

str DeliveryDate = RetailENInfo::formatDatetimeData(purchPurchaseOrderTmp.DeliveryDate, "sv");

HTML formatting in SSRS report using X++

  purchPurchaseOrderTmpLoc.Name   = inventTable.itemName();
        if (externalItemFreeTxt)
        {
            purchPurchaseOrderTmpLoc.Name   = strFmt('%1 <br />', purchPurchaseOrderTmpLoc.Name);
            purchPurchaseOrderTmpLoc.Name += strFmt('<i> %1: %2 </i>', "@SYS342305", externalItemFreeTxt);
        }
        if (barcode)
        {
            purchPurchaseOrderTmpLoc.Name   = strFmt('%1 <br />', purchPurchaseOrderTmpLoc.Name);
            purchPurchaseOrderTmpLoc.Name += strFmt('<i> %1: %2 </i>', "@SYS331679", barcode);
        }
Then in ssrs report designer enable html markup in the text box

DataEntity import Dynamic field mapping X++

using JSONTOXMLConvert;
Public class CommonDataEntityImportService
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name = "Entities"></param>
    /// <returns></returns>
    public CommonDataEntityImportResponseContract importData(Newtonsoft.Json.Linq.JObject    Entities)
    {
        // Define XML Document and its nodes
        XmlDocument     doc;
        XmlNodeList     xmlMainNodeList;
        XmlNodeList     xmlChildNodeList;
        XmlElement      nodeRoot;
        XmlElement      nodeParent;
        XMLParseError   xmlError;
        // Define temporary variables
        int i, j;
        str response;
        Set setResponsetext = new Set(Types::String);

        try
        {
            //passsing and converting JSOn to XML
            
            str xml = Utilities::ConvertToXML(Entities);

            doc = new XmlDocument();
            doc.loadXml(xml);

            // Verify XML Document Structure
            xmlError  = doc.parseError();
            if(xmlError && xmlError.errorCode() != 0)
            {
                throw error(strFmt("XML Error: %1", xmlError.reason()));
            }

            // Get the root element and its child nodes
            nodeRoot = doc.firstChild();
            xmlMainNodeList = nodeRoot.childNodes();

            //looping through all the Parent nodes
            for (i=0; i < xmlMainNodeList.length(); i++)
            {
                Common          common;
                SysDictTable    dictTable;
                SysDictField    dictField;
                str             responseText =  strMin();

                nodeParent          = xmlMainNodeList.item(i);
                xmlChildNodeList    = nodeParent.childNodes();
                str parentNodeName  = nodeParent.name();

                XmlElement  lineNumber;
                XmlElement  orderNumber;
                XmlElement  dataAreadid;

                switch (parentNodeName)
                {
                    case 'PurchaseOrderHeader':
                        dictTable           = new SysDictTable(tableName2Id(tableStr(PurchPurchaseOrderHeaderEntity)));
                        common              = dictTable.makeRecord();
                        orderNumber         = nodeParent.selectSingleNode(fieldStr(PurchPurchaseOrderHeaderEntity, PurchaseOrderNumber));
                        dataAreadid         = nodeParent.selectSingleNode(fieldStr(PurchPurchaseOrderHeaderEntity, DataAreaId));
                        responseText        = strFmt("Purchase order %1", orderNumber.text());

                        select forupdate common
                            where common.(fieldName2id(common.TableId, 'PurchaseOrderNumber')) == orderNumber.text() &&
                             common.(fieldName2id(common.TableId, 'DataAreaId')) == dataAreadid.text();

                        break;
                    case 'PurchaseOrderLinesV2':
                        dictTable           = new SysDictTable(tableName2Id(tableStr(PurchPurchaseOrderLineV2Entity)));
                        common              = dictTable.makeRecord();
                        lineNumber          = nodeParent.selectSingleNode(fieldStr(PurchPurchaseOrderLineV2Entity, LineNumber));
                        orderNumber         = nodeParent.selectSingleNode(fieldStr(PurchPurchaseOrderLineV2Entity, PurchaseOrderNumber));
                        dataAreadid         = nodeParent.selectSingleNode(fieldStr(PurchPurchaseOrderLineV2Entity, DataAreaId));
                        responseText        = strFmt("Purchase order %1", orderNumber.text());
                       
                        select forupdate common
                        where common.(fieldName2id(common.TableId, 'PurchaseOrderNumber')) == orderNumber.text() &&
                            common.(fieldName2id(common.TableId, 'LineNumber')) == str2Int64(lineNumber.text()) &&
                            common.(fieldName2id(common.TableId, 'DataAreaId')) == dataAreadid.text();

                        break;
                }
                
                //looping through all the child nodes
                for (j=0; j < xmlChildNodeList.length(); j++)
                {
                    XmlElement nodeChild = xmlChildNodeList.item(j);

                    str value  = nodeChild.text();

                    dictField = dictTable.fieldObject(fieldName2Id(dictTable.id(), nodeChild.name()));
        
                    if(dictField)
                    {
                        switch (dictField.baseType())
                        {
                            case Types::Int64 :
                                common.(fieldName2Id(common.TableId, nodeChild.name())) = str2Int64(value);
                                break;
                            case Types::Integer :
                                common.(fieldName2Id(common.TableId, nodeChild.name())) = str2Int(value);
                                break;
                            case Types::Date :
                                common.(fieldName2Id(common.TableId, nodeChild.name())) = str2Date(value,321);
                                break;
                            case Types::Real :
                                common.(fieldName2Id(common.TableId, nodeChild.name())) = str2Num(value);
                                break;
                            default :
                                common.(fieldName2Id(common.TableId, nodeChild.name())) = value;
                                break;
                        }
                    }
                
                }
                ttsbegin;
                if (common.RecId)
                {
                    common.update();
                    response = orderNumber.text();
                }
                else
                {
                    common.insert();
                    response = orderNumber.text();
                }
                ttscommit;

            }

            return this.formatResponseToJSON(response);
            
        }
        catch(Exception::CLRError)
        {
            throw Error("CLRError : DLL Error");
        }
        catch(Exception::Error)
        {
            throw Error("unknown Error");
        }
        catch(Exception::DuplicateKeyException)
        {
            throw Error("DuplicateKeyException: Record already exists");
        }
    }

    /// <summary>
    /// generate JSON response
    /// </summary>
    /// <param name = "_set"></param>
    /// <returns></returns>
    public HFGCommonDataEntityImportResponseContract formatResponseToJSON(PurchId _poNum)
    {
        HFGCommonDataEntityImportResponseContract responseContract = new HFGCommonDataEntityImportResponseContract();
        responseContract.parmResponse(_poNum);

        return responseContract;
    }

}

==============

response contarct
[DataContractAttribute]
class CommonDataEntityImportResponseContract
{
    PurchId  response;
    
    [DataMemberAttribute('PurchaseOrderNumber')]
    public PurchId parmResponse(PurchId _response = response)
    {
        response = _response;
        return response;
    }

}
========
JSON payload
{
    "Entities": {
        "PurchaseOrders": [
            {
                "PurchaseOrderHeader": [
                    {
                        "DataAreaId": "100",                        
                        "PurchaseOrderNumber": "6100001105",
                        "OrderVendorAccountNumber": "60000016",
                        "RequestedDeliveryDate": "2023-06-09",
                        "VendorOrderReference": "SO000609C",
                        "ReceivingWarehouseId": "DC01"
                    }
                ],
                "PurchaseOrderLinesV2": [
                    {
                        "DataAreaId": "100",   
                        "LineNumber": 6.00,                     
                        "ItemNumber": "44573054",
                        "ProductConfigurationId": "44573054C001",
                        "OrderedPurchaseQuantity": 1,
                        "RequestedDeliveryDate": "2023-06-09",
                        "ReceivingWarehouseId": "DC01",
                        "PurchasePrice": 4,
                        "PurchaseOrderNumber": "6100001105"
                    }
                ]
            }
        ]
    }
}

======
JSON to XML convesrion using C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Xml.Linq;

namespace JSONTOXMLConvert
{
    public class Utilities
    {
        public static string ConvertToXML(Newtonsoft.Json.Linq.JObject myJObject)
        {
            string json = myJObject.ToString(Newtonsoft.Json.Formatting.None);
            //if an empty string is passed, return empty string without conversion
            if (string.IsNullOrEmpty(json))
                return string.Empty;
            //if invalid json is passed, throw error.
            ValidateJSON(json);
            //Convert Json to XML
            XDocument xmlDoc = JsonConvert.DeserializeXNode(json);
            return xmlDoc.ToString();
        }
        public static void ValidateJSON(string json)
        {
            try
            {
                var jsonObject = JObject.Parse(json);
            }
            catch (Exception ex)
            {
                throw new InvalidCastException("Provided json is not valid.", ex);
            }
        }
    }
}

JumpRef in form extension X++

class PurchTableForm_EventHandler
{
    /// <summary>
    /// JumpRef mthod overrride for form control
    /// </summary>
    /// <param name = "sender"></param>
    /// <param name = "e"></param>
    [FormEventHandler(formStr(PurchTable), FormEventType::PostRun),SuppressBPWarning('BPParameterNotUsed', 'Parameter required')]
    public static void PurchTable_OnPostRun(xFormRun sender, FormEventArgs e)
    {
        FormStringControl   control = sender.design().controlName(formControlStr(PurchTable, TransferOrderId));
        control.registerOverrideMethod(methodStr(FormStringControl, jumpRef), methodStr(PurchTableForm_Extension, jumpRef), sender);
    }

}

/// <summary>
/// Extension for PurchTable form
/// </summary>
[ExtensionOf(formstr(PurchTable))]
final class PurchTableForm_Extension
{
    /// <summary>
    /// JumpRef override method
    /// </summary>
    /// <param name = "_formControl">form controlId</param>
    public void jumpRef(FormControl _formControl)
    {
        MenuFunction	menuFunction;
        Args        	args = new Args();
        PurchTable      purchTable  =_formControl.formRun().dataSource(formDataSourceStr(PurchTable,PurchTable)).cursor() as PurchTable;

        if(purchTable.TransferOrderId)
        {
            InventTransferTable  InventTransferTable = InventTransferTable::find(purchTable.TransferOrderId);

            args.record(InventTransferTable);
            args.lookupRecord(InventTransferTable);

            menuFunction = new MenuFunction(menuitemDisplayStr(InventTransferOrder), MenuItemType::Display);

            menuFunction.run(args);
        }
    }

}

Table browser URL in D365FO

Critical Thinking icon icon by Icons8