Monday, January 29, 2024

Convert Stream to Base64String in D365FO X++

using Microsoft.Dynamics365.LocalizationFramework;


String getBase64FromString(

            System.IO.Stream        _pdfStream)

    {

        str base64data = '';


        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);

                }

            }

        return base64data ;

    }


Condition:

Feature "Utilize application resources to perform CBD documents conversion from Word to PDF format" is enabled,

Then stream aligned to get Base64String.

Workaround logic:

str     fileDownloadURL;

            System.IO.Stream        tempPdfStream;

            fileDownloadURL = File::SendFileToTempStore(_pdfStream, this.parmSaveFilePath());


            tempPdfStream = File::UseFileFromURL(fileDownloadURL);

Tuesday, December 26, 2023

Consume External API in D365FO using .Net library

 using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Net.Http;

using System.Net.Http.Headers;

using System.Text;

using System.Threading.Tasks;

using Newtonsoft.Json;


namespace SAN_NotificationsLibrary

{

    public class SAN_NotificationService

    {

        public void ProcessNotification(string userName, string password, string url, string clientId, string clientSecretKey, string customerId, string subject, int days, string body)

        {

            string tokenPath = "/identity/connect/token";

            var uri = new Uri(url); 

            var accessToken = GetAccessToken($"{uri.Scheme}:

            var client = new HttpClient();

            client.BaseAddress = new Uri($"{uri.Scheme}:


            var request = new HttpRequestMessage(HttpMethod.Post, uri.AbsolutePath);

            client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);

            var data = new

            {

                subject = subject,

                body = body,

                customerNumber = customerId,

                duration = days

            };

            request.Content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");

            var response = client.SendAsync(request).Result;

           

        }


        private string GetAccessToken(string baseUrl, string tokenPath, string clientId, string clientSecret, string userName, string password)

        {

            var client = new HttpClient();

            client.BaseAddress = new Uri(baseUrl);

            var request = new HttpRequestMessage(HttpMethod.Post, tokenPath);


            var byteArray = new UTF8Encoding().GetBytes($"{clientId}:{clientSecret}");

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));


            var postData = new List<KeyValuePair<string, string>>();

            postData.Add(new KeyValuePair<string, string>("grant_type", "password"));

            postData.Add(new KeyValuePair<string, string>("username", userName));

            postData.Add(new KeyValuePair<string, string>("password", password));


            request.Content = new FormUrlEncodedContent(postData);

            var response = client.SendAsync(request).Result;

            var t = response.Content.ReadAsStringAsync().Result;

            var token = JsonConvert.DeserializeObject<Token>(t);

            return token?.AccessToken;

        }


        internal class Token

        {

            [JsonProperty("access_token")]

            public string AccessToken { get; set; }


            [JsonProperty("token_type")]

            public string TokenType { get; set; }


            [JsonProperty("expires_in")]

            public int ExpiresIn { get; set; }


            [JsonProperty("refresh_token")]

            public string RefreshToken { get; set; }

        }

    }



}


Tuesday, December 5, 2023

RemoveRecIdSuspension in D365FO X++

     protected void removeRecIdSuspension()

    {

        TableId         tableId= <Table num>;

appl.sysRecIdSequence().removeRecIdSuspension(tableId);

    }

Monday, October 30, 2023

Inventory Onhand by warehouse for Non-WMS & WMS warehouse in D365FO

 

Table: WHSInventReserve

or

View: WHSInventReserveView

Range: 

HierarchyLevel -> 

0 (Item level)

1 (Site level)

2 (Warehouse level)

...

So on


Field to return value for On hand qty

AvailPhysical


Thursday, September 14, 2023

Copy User information from one to another (Role & Assign organization permission & Usage data) from SQL in D365FO

INSERT INTO SECURITYUSERROLE (USER_, SECURITYROLE, ASSIGNMENTMODE, ASSIGNMENTSTATUS, VALIDFROM, VALIDTO, VALIDFROMTZID, VALIDTOTZID)

SELECT '<to user>',SECURITYROLE, ASSIGNMENTMODE, 

ASSIGNMENTSTATUS,VALIDFROM, VALIDTO, VALIDFROMTZID, VALIDTOTZID FROM SECURITYUSERROLE 

WHERE USER_ in ('<from user>') ;


INSERT INTO omUserRoleOrganization (USER_, OMHIERARCHYTYPE, OMINTERNALORGANIZATION, SECURITYROLE, SECURITYROLEASSIGNMENTRULE)

SELECT '<to user>',OMHIERARCHYTYPE, OMINTERNALORGANIZATION, 

SECURITYROLE,SECURITYROLEASSIGNMENTRULE FROM omUserRoleOrganization 

WHERE USER_ in ('<from user>');


INSERT INTO SYSLASTVALUE (USERID, RECORDTYPE, ELEMENTNAME, DESIGNNAME, ISKERNEL, COMPANY,VALUE,DOCUMENT)

SELECT '<to user>',RECORDTYPE, ELEMENTNAME, 

DESIGNNAME,ISKERNEL,COMPANY,VALUE,DOCUMENT FROM SYSLASTVALUE 

WHERE USERID in ('<from user>');

Monday, July 3, 2023

Confirm PO without Purchase confirmation journal in D365FO X++

 VersioningPurchaseOrder::newPurchaseOrder(<purchTable>).confirm();


Logic:

[ExtensionOf(classStr(VersioningPurchaseOrder))]
final class VersioningPurchaseOrderCls_SAN_Extension
{
    protected boolean isChangeConfirmationRequired(Common _newRecord, Common _oldRecord)
    {
        boolean ret;
        PurchTable   purchTableloc;
        TableId     tableId = (_oldRecord ? _oldRecord.TableId : _newRecord.TableId);
        ret = next isChangeConfirmationRequired(_newRecord, _oldRecord);
        switch (tableId)
        {
            case tableNum(PurchTable):
                purchTableLoc = _newRecord;
                if (purchTableLoc.IsIntLog)
                {
                    ret = false;
                }
        }
        return ret;
    }
}

Friday, June 16, 2023

Business event related tables in D365FO (For migration)

 BusinessEventsEndpoint, 

BusinessEventsAzureEndpoint (For Azure endpoint), 

BusinessEventsFlowEndpoint (For Flow endpoint), 

BusinessEventsConfiguration (Activate related with company)


Entity:

BusinessEventsConfigurationEntityV2 (Business events configuration)

BusinessEventsEndpointEntityV2 (Business events endpoint)

Monday, May 15, 2023

SQL Keywords

STRING_AGG

SQL Query:

select STRING_AGG(erc.Code, ';') as ProductLine From EcoResCategory erc

join EcoResProductCategory erpc

on erc.RecId = erpc.Category 

join INVENTTABLE it

on erpc.Product  = it.PRODUCT

where  it.ITEMID  = 'TST702'  and erc.Code  != '' and it.DATAAREAID = 'USMF' 

Output: 

2;7;13;G;9;3;Z;11;17;D;B;F;8;6;1;05


Execute:


Execute ('

Declare @val Varchar(MAX)

Select @val = COALESCE(@val + '','' + erc.Code, erc.Code) 

        From EcoResCategory erc

join EcoResProductCategory erpc

on erc.RecId = erpc.Category 

join INVENTTABLE it

on erpc.Product  = it.PRODUCT

where  it.ITEMID  = 'TST702'  and erc.Code  != '' and it.DATAAREAID = 'USMF' 

Group by erc.Code order by erc.Code asc

Select @val')


COALESCE

Declare @val Varchar(MAX)

Select @val = COALESCE(@val + ';' + erc.Code, erc.Code) 

        From EcoResCategory erc

join EcoResProductCategory erpc

on erc.RecId = erpc.Category 

join INVENTTABLE it

on erpc.Product  = it.PRODUCT

where  it.ITEMID  = 'TST702'  and erc.Code  != '' and it.DATAAREAID = 'USMF' 

Group by erc.Code order by erc.Code asc

Select @val


Tuesday, May 9, 2023

Get ER format mapping from Print management destination setting in D365FO X++

ERFormatMappingId                   formatMapping;

 str defaultReportName = PrintMgmtDocType::construct(PrintMgmtDocumentType::SAN_CommercialInvoice).getDefaultReportFormat();

        if(defaultReportName)

        {

            int prefixLength = strLen(ERPrintMgmtSetupUISettingsCtlEventHandler::PrintManagementFormatPrefix);

            var formatGuid = str2Guid(subStr(defaultReportName, prefixLength + 1, strLen(defaultReportName) - prefixLength));


            formatMapping = ERFormatMappingTable::findByGUID(formatGuid).RecId;

        }

Skip Inventory reservation on Sales order lines in D365FO

[ExtensionOf(classStr(InventUpd_Reservation))] final class InventUpd_ReservationCls_SAN_Extension {     void updateNow()     {         if(mo...