Tuesday, December 13, 2022

D365FO: Inventory marking between purchase order and transfer order

/// create/Update marking between purhcase order and transfer order
    /// </summary>
    /// <param name = "_inventTransId">receipt InventTrans PO</param>
    /// <param name = "_refInventTransId">Issue InventTrans TO</param>
    /// <param name = "_qtyToMark">qty</param>
    public void updateMarking(InventTransId   _inventTransId,
                                InventTransId   _refInventTransId,
                                Qty             _qtyToMark = 0)
    {
        Qty qtyToMark;
        try
        {
            TmpInventTransMark	  tmpInventTransMark;

            InventTransId         issueInventTransId   = _inventTransId;
            InventTransId         receiptInventTransId = _refInventTransId;

            InventTransOriginId receiptInventTransOriginId = InventTransOrigin::findByInventTransId(receiptInventTransId).RecId;
            InventTrans receiptInventTrans = InventTrans::findByInventTransOrigin(receiptInventTransOriginId);
            
            InventTransOriginId issueInventTransOriginId = InventTransOrigin::findByInventTransId(issueInventTransId).RecId;
            InventTrans issueInventTrans = InventTrans::findByInventTransOrigin(issueInventTransOriginId);
            
            InventTransMarkCollection collection = TmpInventTransMark::markingCollection(
            InventTransOrigin::find(receiptInventTransOriginId), receiptInventTrans.inventDim(), receiptInventTrans.Qty);
 
            collection.insertCollectionToTmpTable(tmpInventTransMark);

            select firstonly tmpInventTransMark
                where tmpInventTransMark.InventTransOrigin == issueInventTrans.InventTransOrigin
                    && tmpInventTransMark.InventDimId       == issueInventTrans.InventDimId;
 
            if (tmpInventTransMark.RecId != 0)
            {
                qtyToMark = issueInventTrans.Qty;
               
                tmpInventTransMark.QtyMarkNow =  qtyToMark;
                tmpInventTransMark.QtyRemain  -= tmpInventTransMark.QtyMarkNow;
              
                Map mapUpdated = new Map(Types::Int64, Types::Record);
                mapUpdated.insert(tmpInventTransMark.RecId, tmpInventTransMark);
 
                TmpInventTransMark::updateTmpMark(
                    receiptInventTransOriginId,
                    receiptInventTrans.inventDim(),
                    -qtyToMark,
                    mapUpdated.pack());
            }
        }
        catch (Exception::Error)
        {
            throw error(strFmt("FailMarkInventtransaction", _refInventTransId));
        }
    }

Monday, December 12, 2022

D365FO IDisposable context class

Scenario: pass additional parameter to a method that doesnt have a parametr signature 
After the execution of using code block , Dispose method will be called.

IDisposible is a singleton instance of a class per session, for example if you open two different tabs and run the code you will get two different instance of the class
class DocTypeFile_CUSTOM_Context implements System.IDisposable
{
    static DocTypeFile_CUSTOM_Context  docTypeFileContext;

    public  boolean overrideDefaultDocType = false;
    public boolean printSalesInvoiceReport;
    public boolean printSalesConfReport;
   // public PrintMgmtDocumentType printMgmtDocumentType;
   public DocuTypeId doucTypeId = strMin();
  
    public void new()
    {
        if(docTypeFileContext)
        {
            throw error("NestingIsNotSupported");
        }
        docTypeFileContext = this;
    }

    public void dispose()
    {
        docTypeFileContext = null;
    }

    static public DocTypeFile_CUSTOM_Context current()
    {
        return  docTypeFileContext;
    }

}
/// <summary>
///     To handle the report design to print based on caller
/// </summary>
[ExtensionOf(classStr(SalesInvoiceController))]
final class SalesInvoiceController_CUSTOM_Extension
{
    /// <summary>
    ///     choose report design
    /// </summary>
    protected void outputReport()
    {
		//initalize disposible context class 
        using (var docTypeFileContext = new DocTypeFile_CUSTOM_Context())
        {
            SRSPrintDestinationSettings srsPrintDestinationSettings = formLetterReport.getCurrentPrintSetting().parmPrintJobSettings();
           
            if (srsPrintDestinationSettings.printMediumType() == SRSPrintMediumType::File)
            {
			   docTypeFileContext.overrideDefaultDocType = true;
               docTypeFileContext.doucTypeId = "File";
            }

            next outputReport();
        }
    }

}
[ExtensionOf(tableStr(DocuType))]
final class DocuType_CUSTOM_Extension
{
    static DocuTypeId typeFile()
    {
        DocuTypeId docuTypeId;
        docuTypeId = next typeFile();

        DocTypeFile_CUSTOM_Context  docTypeFileContext = DocTypeFile_CUSTOM_Context::current();

        if(docTypeFileContext && docTypeFileContext.overrideDefaultDocType)
        {
            docuTypeId = docTypeFileContext.doucTypeId;
        }

        

        return docuTypeId;
    }

}

Monday, December 5, 2022

Release Number sequence X++

  NumberSeq::release(numSeq.parmNumberSequenceCode(), "Number Seq to be released");
Example
  NumberSeq::release("@AR26", CustTable.AccountNum);

Wednesday, November 30, 2022

D365FO: Zip/Unzip memory stream to byte[] array X++

Sometimes we have to deal with big file streams, during that scenario there is an option to zip/unzip the file using gzip in X++.

for example: Pass files larger than 25MB to logic apps, logic app has a file size limit of 25 MB
using System.IO;
using System.IO.Compression;


class ZipUnzip
{
    public static System.Byte[] Compress(System.Byte[] data)
    {
        var compressedStream = new MemoryStream();
        var zipStream = new GZipStream(compressedStream, CompressionMode::Compress);
        zipStream.Write(data, 0, data.Length);
        zipStream.Close();
        return compressedStream.ToArray();
    }

    public static System.Byte[] Decompress(System.Byte[] data)
    {
        var compressedStream = new MemoryStream(data);
        var zipStream = new GZipStream(compressedStream, CompressionMode::Decompress);
        var resultStream = new MemoryStream();

        System.Byte[] buffer = new System.Byte[4096]();
        int read;

        do
        {
            read = zipStream.Read(buffer, 0, buffer.Length);
            resultStream.Write(buffer, 0, read);
        }
        while(read);

        return resultStream.ToArray();
    }

}

Thursday, November 24, 2022

D365FO: RESET TTS LEVEL

internal final class resettts
{
    /// <summary>
    /// Class entry point. The system will call this method when a designated menu 
    /// is selected or when execution starts and this class is set as the startup class.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        while (appl.ttsLevel() > 0)
        {
            info(strfmt("Level %1 aborted",appl.ttsLevel()));
            ttsAbort;
        }
    }

}

D365FO: Test Webservices using SoapUI

 

In soap UI create a new test suite and create a new POST Http request with below values

Request URL: https://login.microsoftonline.com/YourTenant.onmicrosoft.com/oauth2/token

client_id : xxxxxxx-xxx-xxxx-xxx-xxxxxxxxxx

client_secret : xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Resource : https://onebox.sandbox.operations.dynamics.com

grant_type : client_credentials

 Post Query string : checked

 


Run the request copy the access token from the JSON window into a notepad

Append bearer before the access token

Example

bearer  eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik1yNS1BVWliZkJpaTdOZDFqQmViYXhib1hXMCIsImtpZCI6Ik1yNS1BVWliZkJpaTdOZDFqQmViYXhib1hXMCJ9.eyJhdWQiOiJodHRwczovL3RkY2NhZHlwcmVwcm9kLnNhbmRib3gub3BlcmF0aW9ucy5keW5hbWljcy5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9lOGRjZjZlNi0zYWNjLTRhZjktOWNiMi03N2Y2ODhjYjY4OGIvIiwiaWF0IjoxNjQ0NDg3ODcwLCJuYmYiOjE2NDQ0ODc4NzAsImV4cCI6MTY0NDQ5MTc3MCwiYWlvIjoiRTJaZ1lDaWI4ZjNWOUNmL2p1aG5Xd1FzWTNXcUFnQT0iLCJhcHBpZCI6IjEyYzFhY2RmLTAzNjktNDk3OC1hYWQzLTM3OGQxY2I3NTM5ZSIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2U4ZGNmNmU2LTNhY2MtNGFmOS05Y2IyLTc3ZjY4OGNiNjg4Yi8iLCJvaWQiOiIzNDJlNDMyOC02ZGM3LTQ1MjItYjcwMS1iOWQ4Yzc1N2NmNzUiLCJyaCI6IjAuQVFzQTV2YmM2TXc2LVVxY3NuZjJpTXRvaXhVQUFBQUFBQUFBd0FBQUFBQUFBQUFMQUFBLiIsInJvbGVzIjpbIkNvbm5lY3Rvci5GdWxsQWNjZXNzIl0sInN1YiI6IjM0MmU0MzI4LTZkYzctNDUyMi1iNzAxLWI5ZDhjNzU3Y2Y3NSIsInRpZCI6ImU4ZGNmNmU2LTNhY2MtNGFmOS05Y2IyLTc3ZjY4OGNiNjg4YiIsInV0aSI6IkJoSjFEaUYxb2thd0NsOURtZVE5QUEiLCJ2ZXIiOiIxLjAifQ.EKQ8IVQEzHmJ5W2L0p80HnPKCP86tOgXyT5FuM4OBDeNotxbSPSXPhqq9CV3qNBSUY9l0KXcbla1rDNd7SrZv079oeOsCZaDoTp4L4D8IeYfTAzoSKhmcm3ljaLZIBw4XWC5kcG1pn_o19uDDj9OzBDM9RzUrfwyy-X-TOewBApQe5oEzhwMoTsFrzod6u_8x_tXtWoqjCfWwzbC7bH9jsDMc3cKX4NdebHDdeklIDY9j1kHc3rTYxDlhcu6kLQeN2WVajuuhs52s56YXfJj4Dpz7alTsfIpHeCc5icnijwJx3BQ03kUH2cqFfl6KttowO-cjiBUix2dX3HqTAfN1Q

 

Copy the access modified text then go to the request and add Authorization into the Header of the request and paste the text as value




 

Also remove the optional tags in the call context.

D365FO:Delete BatchJob History through SQL query

--delete from batchJobHistory where createdDateTime < '2020-12-31 16:00:49.000'

--DELETE    FROM batchHistory
--WHERE BatchJobHistoryId NOT IN
--    (SELECT RECID FROM batchJobHistory )

--DELETE    FROM constraintHistory
--WHERE DependsOnBatchId NOT IN
--    (SELECT RECID FROM batchHistory )

D365FO:Cancel Purchase order through X++

 Create a new class and extend standard PurchCancel class

class PurchCancel_CUSTOM extends PurchCancel
{
    public void cancelPO(PurchTable _PurchTable)
    {
        PurchCancel_CUSTOM purchCancel = PurchCancel_CUSTOM::construct();
        purchCancel.parmPurchTable(_PurchTable);
       // purchTable = _PurchTable;
        purchCancel.run();
    }

    static PurchCancel_CUSTOM construct()
    {
        return new PurchCancel_CUSTOM();
    }

    void new()
    {
        super();
    }
}

Wednesday, November 16, 2022

SalesInvoice change file name when using print management with File DocumentType

/// <summary>
///     To handle the report design to print based on caller
/// </summary>
[ExtensionOf(classStr(SalesInvoiceController))]
final class SalesInvoiceController_MY_Extension
{
    /// <summary>
    ///     choose report design
    /// </summary>
    protected void outputReport()
    {
        Args controllerArgs = this.parmArgs();
        SRSCatalogItemName  reportDesign;
        if((controllerArgs.menuItemName() == menuItemOutputStr(SalesInvoice_CUSTOM)) || custInvoiceJour.isProforma() || (controllerArgs.menuItemName() == menuItemOutputStr(SalesInvoice)))
        {            
            reportDesign = ssrsReportStr(SalesInvoice_Custom,Report_Custom);
        }
        else 
        {
            reportDesign = ssrsReportStr(SalesInvoice_Custom,Report);
        }
        this.parmReportName(reportDesign);
        this.parmReportContract().parmReportName(reportDesign);

        SRSPrintDestinationSettings srsPrintDestinationSettings = formLetterReport.getCurrentPrintSetting().parmPrintJobSettings();
        SRSPrintMediumType srsPrintMediumType = srsPrintDestinationSettings.printMediumType();
        formletterReport.parmReportRun().settingDetail().parmReportFormatName(reportDesign);

        if (srsPrintDestinationSettings.printMediumType() == SRSPrintMediumType::File)
        {
            srsPrintDestinationSettings.fileName(custInvoiceJour.InvoiceId);
        }
        srsPrintDestinationSettings.overwriteFile(true);

        next outputReport();
    }

Table browser URL in D365FO

Critical Thinking icon icon by Icons8