Monday, January 30, 2023

Spliting Online store transaction in D365FO X++

//Online store transaction - Retail synchronize order

[ExtensionOf(classStr(RetailSyncOrdersSchedulerTask))]

final class RetailSyncOrdersSchedulerTaskCls_POL_Extension

{

    public void run()

    {

        Array             listOfCurTransactions, listOfTransactionsPostOrderSplit;


        listOfTransactionsPostOrderSplit= new Array(Types::Int64);

         listOfCurTransactions = Array::create(this.parmPackedTransactionRecIdList());


        listOfTransactionsPostOrderSplit= SANOrderSplit::splitOrders( listOfCurTransactions);

        this.parmPackedTransactionRecIdList(listOfTransactionsPostOrderSplit.pack());


        next run();

    }


}

Wednesday, January 25, 2023

Azure copy & move files from Blob storage in D635FO X++

 using Microsoft.Azure;

using Microsoft.WindowsAzure.Storage;

using Microsoft.WindowsAzure.Storage.Blob;


using Microsoft.WindowsAzure.Storage.Auth;

using Microsoft.Dynamics.AX.Framework.FileManagement;

using fileShareStorage = Microsoft.WindowsAzure.Storage.File;


class SANAzureBlobFileMove

{

    /// <summary>

    /// Runs the class with the specified arguments.

    /// </summary>

    /// <param name = "_args">The specified arguments.</param>

    public static void main(Args _args)

    {

        SAN_FileIntegrationParameters   fileParameters;

        str                             azureBlobFolderPath;

        CloudBlobClient                 blobClient;

        Filename                        folderPath ='DailyPortalOrder';

        Name                            containerReference = 'dp';

        str                             fileName;

        #File


        fileName = 'TestFile.Txt';

        fileParameters = SAN_FileIntegrationParameters::find();


        KeyVaultCertificateTable    certificateTable= KeyVaultCertificateTable::findByName(fileParameters.AuthorizationSecretName);

        str keyvaultValue   = KeyVaultCertificateHelper::getManualSecretValue(certificateTable.RecId);


        if (fileParameters.AuthorizationSecretName == "")

        {

            throw error("Key vault authorization secert must be specified");

        }


        try

        {

            System.Uri  uri = new System.Uri(keyvaultValue);

            blobClient = new CloudBlobClient(uri);

            if (folderPath)

            {

                azureBlobFolderPath = containerReference + #FilePathDelimiter + folderPath;

            }

            else

            {

                azureBlobFolderPath = containerReference;

            }

            

            CloudBlobContainer blobcontainer = blobClient.GetContainerReference(azureBlobFolderPath);

            CloudBlobContainer sourceBlobcontainer = blobClient.GetContainerReference(containerReference);

            CloudBlobContainer destBlobcontainer = blobClient.GetContainerReference(containerReference);

            /*

            CloudBlobDirectory  cloudBlobDirectory;

            Container  con;

            cloudBlobDirectory = blobcontainer.GetDirectoryReference("DailyPortalOrder");

            System.Collections.IEnumerable lstEnumarable = cloudBlobDirectory.ListBlobs(false, 0, null, null);

            System.Collections.IEnumerator lstEnumarator = lstEnumarable.GetEnumerator();

            List filenames = new List(Types::String);

            while(lstEnumarator.MoveNext())

            {

                IListBlobItem item = lstEnumarator.Current;

                if(item is CloudBlockBlob)

                {

                    CloudBlockBlob blob = item;

                    blob.FetchAttributes(null, null, null);

                    con = str2con(blob.name, "/");

                    filenames.addStart(conPeek(con,conlen(con)));

                    info(blob.name);

                    //System.IO.StreamReader  reader = new System.IO.StreamReader(blob.OpenRead(null, null, null));

                    //Info(reader.ReadToEnd());

                }

            }

            */


            System.Byte[] reportBytes = new System.Byte[0]();

            System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();

            reportBytes = enc.GetBytes("SAN TEST TEXT");

            System.IO.MemoryStream stream = new System.IO.MemoryStream(reportBytes);

            CloudBlockBlob      blockBlob = blobcontainer.GetBlockBlobReference(fileName);

            blockBlob.UploadFromByteArray(stream.ToArray(),0,stream.ToArray().Length, null,null,null);


            info(strfmt("updloaded to file path %1 %2 %3", fileName, fileParameters.AzureStorageAccountName, azureBlobFolderPath));


            CloudBlobDirectory sourceCloudBlobDirectory = sourceBlobcontainer.GetDirectoryReference("DailyPortalOrder/");

            CloudBlobDirectory destinationCloudBlobDirectory = destBlobcontainer.GetDirectoryReference("DailyPortalOrder/archive");

            CloudBlockBlob SourceBlob = sourceCloudBlobDirectory.GetBlockBlobReference(fileName);

            CloudBlockBlob destinationBlob = destinationCloudBlobDirectory.GetBlockBlobReference(fileName);

            destinationBlob.UploadFromStream(blockBlob.OpenRead(null,null,null),null,null,null);

            blockBlob.Delete(0,null,null,null);

            

            CloudBlockBlob      blockBlob = blobcontainer.GetBlockBlobReference(_fileName);

            blockBlob.UploadFromByteArray(_memoryStream.ToArray(),0,_memoryStream.ToArray().Length, null,null,null);

        }

        catch(Exception::Error)

        {

            error("Error on file processing");

        }

    }


}


Monday, January 23, 2023

Sync D365FO/AX table to Commerce DB in D365FO


Subscribe to Event handler.

    [SubscribesTo(classStr(RetailCDXSeedDataBase), delegateStr(RetailCDXSeedDataBase, registerCDXSeedDataExtension))]

    public static void RetailCDXSeedDataBase_registerCDXSeedDataExtension(str originalCDXSeedDataResource, List resources)

    {

        if (originalCDXSeedDataResource == resourceStr(RetailCDXSeedDataAX7))

        {

            resources.addEnd(resourceStr(SAN_SalesOrderClassResource));

            resources.addEnd(resourceStr(smmBusRelSectorTableResource));

        }

    }


Create D365FO resource (SAN_SalesOrderClassResource) for new table.

Resource content: XML

<RetailCdxSeedData ChannelDBMajorVersion="7" ChannelDBSchema="ext" Name="AX7">

   <Subjobs>

       <Subjob Id="SAN_SalesOrderClass" TargetTableSchema="ext" AxTableName="SAN_SalesOrderClass">

           <ScheduledByJobs>

               <ScheduledByJob>1140</ScheduledByJob>

           </ScheduledByJobs>

           <AxFields>

              <Field Name="SALESORDERCLASS"/>

<Field Name="MAXQTY"/>

<Field Name="AVAILABLEFROM"/>

<Field Name="AVAILABLETO"/>

<Field Name="SOALLOCPRIORITY"/>

<Field Name="PAYMTERMID"/>

<Field Name="HOLDCODE"/>      

<Field Name="RECID"/>

    <Field Name="RECVERSION"/>

    <Field Name="PARTITION"/>

            </AxFields>

       </Subjob>

   </Subjobs>

</RetailCdxSeedData>


Tuesday, January 17, 2023

Embedded PDF stream to XML in D365FO X++

 

Embedded PDF stream to XML in D365FO X++


We can use either code 1 or code 2,


Code:1

Public System.Xml.XmlElement embed(

            System.Xml.XmlElement   _parentElement,

            Name                    _elementName,

            System.IO.Stream        _pdfStream)

    {

System.Xml.XmlDocument      document;

System.Xml.XmlElement       element;

System.Xml.XmlDocument      ownerDocument;


System.Byte[]               bytes;

    System.IO.BinaryReader      binaryReader;

    System.IO.Stream            baseStream;

    System.IO.StreamReader      streamReader;

    System.Object               streamObject;

    System.Object               bytesObject;

    System.Xml.XmlCDataSection  cdata;


int                         streamLength;

    int                         bytesLength;

    str                         base64data;


        element = document.CreateElement(_elementName);


        if (_pdfStream != null)

        {

            baseStream      = _pdfStream;

            streamObject    = baseStream.get_Length();

            streamLength    = streamObject;

            binaryReader    = new System.IO.BinaryReader(baseStream);

            bytes           = binaryReader.ReadBytes(streamLength);


            baseStream.Close();


            ownerDocument   = element.get_OwnerDocument();

            bytesObject     = bytes.get_Length();

            bytesLength     = bytesObject;

            base64data      = System.Convert::ToBase64String(bytes, 0, bytesLength);

            cdata           = ownerDocument.CreateCDataSection(base64data);


            element.AppendChild(cdata);

        }


        _parentElement.AppendChild(element);


        return element;

    }


Code 2:

System.Xml.XmlElement embed(

            System.Xml.XmlElement   _parentElement,

            Name                    _elementName,

            System.IO.Stream        _pdfStream)

    {

        element = document.CreateElement(_elementName);


        if (_pdfStream != null)

        {

            using (System.IO.Stream fileStream = _pdfStream)

            {

                using (System.IO.MemoryStream memoryStream = new System.IO.MemoryStream())

                {

                    fileStream.CopyTo(memoryStream);

                    base64data =  ERConversionUtils::StreamToBase64(memoryStream);

                    ownerDocument   = element.get_OwnerDocument();

                    cdata           = ownerDocument.CreateCDataSection(base64data);

                    element.AppendChild(cdata);

                }

            }

        }


        _parentElement.AppendChild(element);


        return element;

    }

Friday, January 6, 2023

SQL Query to fetch Related information based on transaction type from TaxTrans in D365FO

//Query to Fetch Related information based on transaction type and tagged Masters (Customer/Vendor) from 

Posted Sales Tax

1. Type (Customer or vendor or ledger)

2. Identification (Customer or vendor account name or Voucher entries text)

//These columns also be converted to Computed column (T-SQL) in view.


Query:

 CAST

                 ((SELECT TOP (1) CAST((CASE WHEN tt.Voucher =

                                   (SELECT TOP (1) ct.Voucher

                                   FROM    CUSTTRANS AS ct

                                   WHERE ct.VOUCHER = tt.VOUCHER AND ct.TRANSDATE = tt.TRANSDATE AND ct.DATAAREAID = tt.DATAAREAID) THEN 'Customer' ELSE CASE WHEN tt.Voucher =

                                   (SELECT TOP (1) vt.Voucher

                                   FROM    VendTrans AS vt

                                   WHERE vt.VOUCHER = tt.VOUCHER AND vt.TRANSDATE = tt.TRANSDATE AND vt.DATAAREAID = tt.DATAAREAID) THEN 'Vendor' ELSE 'Ledger' END END) AS NVARCHAR(10)) AS Expr1

                  FROM    dbo.TAXTRANS AS tt

                  WHERE (RECID = T1.RECID)) AS NVARCHAR(60)) AS TYPE,


 

CAST

                 ((SELECT TOP (1) dpt.NAME

                  FROM    dbo.CUSTTRANS AS ct INNER JOIN

                               dbo.CUSTTABLE AS ctab ON ctab.ACCOUNTNUM = ct.ACCOUNTNUM AND ct.DATAAREAID = ctab.DATAAREAID INNER JOIN

                               dbo.DIRPARTYTABLE AS dpt ON dpt.RECID = ctab.PARTY

                  WHERE (ct.VOUCHER = T1.VOUCHER) AND (ct.TRANSDATE = T1.TRANSDATE) AND (ct.DATAAREAID = T1.DATAAREAID)

                  UNION ALL

                  SELECT TOP (1) dpt.NAME

                  FROM   dbo.VENDTRANS AS vt INNER JOIN

                               dbo.VENDTABLE AS vtab ON vtab.ACCOUNTNUM = vt.ACCOUNTNUM AND vt.DATAAREAID = vtab.DATAAREAID INNER JOIN

                               dbo.DIRPARTYTABLE AS dpt ON dpt.RECID = vtab.PARTY

                  WHERE (vt.VOUCHER = T1.VOUCHER) AND (vt.TRANSDATE = T1.TRANSDATE) AND (vt.DATAAREAID = T1.DATAAREAID)

                  UNION ALL

                  SELECT TOP (1) gjae.TEXT

                  FROM   dbo.GENERALJOURNALENTRY AS gje INNER JOIN

                               dbo.GENERALJOURNALACCOUNTENTRY AS gjae ON gjae.GENERALJOURNALENTRY = gje.RECID

                  WHERE (NOT EXISTS

                                   (SELECT TOP (1) VOUCHER

                                   FROM    dbo.CUSTTRANS AS ct2

                                   WHERE (VOUCHER = T1.VOUCHER) AND (TRANSDATE = T1.TRANSDATE) AND (DATAAREAID = T1.DATAAREAID))) AND (NOT EXISTS

                                   (SELECT TOP (1) VOUCHER

                                   FROM    dbo.VENDTRANS AS vt2

                                   WHERE (VOUCHER = T1.VOUCHER) AND (TRANSDATE = T1.TRANSDATE) AND (DATAAREAID = T1.DATAAREAID))) AND (gje.SUBLEDGERVOUCHER = T1.VOUCHER) AND (gje.ACCOUNTINGDATE = T1.TRANSDATE) AND 

                               (gje.SUBLEDGERVOUCHERDATAAREAID = T1.DATAAREAID)) AS NVARCHAR(100)) AS IDENTIFICATION 

FROM   dbo.TAXTRANS AS T1

Capture all Error logs trace in D365FO

    [SubscribesTo(classStr(Info), delegateStr(Info, onInfoLogMessageAdd))]

    public static void Info_onInfoLogMessageAdd(InfoLogMessageAddEventArgs _eventArgs)

    {

        SANPOCDebugTable    sanPOCDebugTable; (Enable with CreatedDateTime)

        boolean                      iscallStackUserEnabled;

            iscallStackUserEnabled = true;//Added custom checkbox on custom user setting

                   if(_eventArgs.exception == Exception::Info || 

                           _eventArgs.exception == Exception::Warning)

                    {

                        //If want to skip validation
                    }

                  else

                {

                sanPOCDebugTable.clear();

                sanPOCDebugTable.initValue();

                sanPOCDebugTable.RunByuserId = curuserid();

                sanPOCDebugTable.Exception = _eventArgs.exception;

                sanPOCDebugTable.InfologStr = _eventArgs.message;

                sanPOCDebugTable.CallStack = xSession::xppCallStack();

                sanPOCDebugTable.insert();

                }

}

//Create new form and add table on it -> Add button to import log information

//To Clean up -> Create batch run -> run to clean up data for past 90 days

//To add this new log form -> generic to all form UI. (To review logs)

Ref: Blog on Microsoft Dynamics AX/ D365: To add dynamics default controls on UI in D365FO (sangeethwiki.blogspot.com)

Convert Call stack to readable format in D365FO X++

//Input --container _xppCallStack = xSession::xppCallStack();  Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFr...