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)

Replaces the value of the specified dimension attribute from source to target in D365FO

Replaces the value of the specified dimension attribute from source to target => LedgerDimensionDefaultFacade::serviceReplaceAttributeVal...