Showing posts with label D365. Show all posts
Showing posts with label D365. Show all posts

Friday, 12 January 2024

Using Expressions in Query Ranges

 The following code programmatically adds a range to a query and uses string substitution to specify the data source and field name. The range expression is associated with the CustTable.AccountNum field; however, because the expression specifies the data sources and field names, the expression can be associated with any field in the CustTable table.

This example can be useful when there is a scenario of adding OR conditions on to query build data source ranges.

static void AddRangeToQuery3Job(Args _args)

    {

        Query q = new Query();  // Create a new query.

        QueryRun qr;

        CustTable ct;

        QueryBuildDataSource qbr1;

        str strTemp;

        ;

    

        // Add a single datasource.

        qbr1 = q.addDataSource(tablenum(CustTable));

        // Name the datasource 'Customer'.

        qbr1.name("Customer");

    

        // Create a range value that designates an "OR" query like:

        // customer.AccountNum == "4000" || Customer.CreditMax > 2500.

    

        // Add the range to the query data source.

        qbr1.addRange(fieldNum(CustTable, AccountNum)).value(

        strFmt('((%1.%2 == "4000") || (%1.%3 > 2500))',

            qbr1.name(),

            fieldStr(CustTable, AccountNum),

            fieldStr(CustTable, CreditMax)));

    

        // Print the data source.

        print qbr1.toString();

        info(qbr1.toString());

    

        // Run the query and print the results.

        qr = new QueryRun(q);

    

        while (qr.next())

        {

            if (qr.changedNo(1))

            {

                ct = qr.getNo(1);

                strTemp = strFmt("%1 , %2", ct.AccountNum, ct.CreditMax);

                print strTemp;

                info(strTemp);

            }

        }

        pause;

    }

Wednesday, 22 November 2023

Map as parameters in X++

 We might have some challenges in using map as a parameter in the contract classes. Usually contract classes in SysOperation framework  we may have to have a map as a parameter so the calculated map can be passed to the service classed.

These scenarios might arise mostly in case of Multi threading  where the records will be split and passed in to the contract parameter. Most of the cases we use containers in the contract class and pass the containers as maps and other collection classes are not allowed.

He is a scenario where list of items and prices should be passed in contract class. We cannot pass a map in to contract class and so if we try to use the containers then multiple values cannot be passed.


Below is a code example to achieve this scenario.


Map             map = new Map(Types::String, Types::Real);
    MapEnumerator   me;
    
    container       cnt;
    str             xml;
    XmlDocument     xmlDocument;
 
map.insert("ItemA", 100);
map.insert("ItemB", 200);
map.insert("ItemC", 300);
map.insert("ItemD", 400);
 
    // pack Map to container
    cnt = map.pack();

Now this container can be passed on to the contract class.


//unpack container to map
To get back the map from the container in the service class we can use the below code

   map = Map::create(cnt);


Similar way to get the map as XML and create a map from XML we can use the below code.
 
    // pack/unpack Map to/from XML
    xml         = map.xml();
    xmlDocument = XmlDocument::newXml(xml);
    map         = Map::createFromXML(xmlDocument.root() as XmlNode);

Wednesday, 8 November 2023

Order Promising

 

  • Order promising helps you reliably promise delivery dates to your customers
  • Order promising calculates earliest ship and receipt dates based on delivery date control method and transport days

Delivery Date Control Methods

  • Sales lead time - based on default number of days, doesn't consider stock availability, known demand, or planned supply
  • ATP (available-to-promise) - includes uncommitted inventory, lead times, planned receipts, and issues
  • ATP + Issue margin - shipping date equals ATP date plus issue margin for the item
  • CTP (capable-to-promise) - availability calculated through explosion, not allowed with Planning Optimization
  • CTP for Planning Optimization - use CTP calculation provided by Planning Optimization

Updating Order Promising Information

  • Order promising information is updated only if existing date can't be fulfilled
  • If current date can't be met, order promising is triggered
  • If current date can still be fulfilled, order promising isn't triggered and current date remains

ATP Calculations

  • ATP quantity calculated using 'cumulative ATP with look-ahead' method
  • ATP quantity includes uncommitted inventory balance in first period
  • ATP quantity calculated for each period in which a receipt is scheduled
  • ATP calculated based on formula ATP = ATP for previous period + Receipts for current period - Issues for current period - Net issue quantity for each future period
  • ATP quantity always greater than or equal to 0
  • Negative ATP quantity automatically set to 0

ATP Backward Demand and Supply

  • ATP backward demand time fence controls how far back to look for delayed demand orders or inventory issues
  • ATP backward supply time fence controls how far back to look for delayed supply orders or inventory receipts
  • ATP delayed demand offset time and ATP delayed supply offset time control when delayed demand or supply considered
  • Example: 7 entered in ATP backward demand and supply time fence fields, and 1 in ATP delayed demand and supply offset time fields

CTP Calculations

  • CTP functionality provides realistic delivery dates based on existing inventory, production capacity, and transportation times.
  • It considers availability of both materials and capacity, giving a more accurate picture of whether demand can be satisfied within a given time frame.

CTP for Planning Optimization

  • CTP for Planning Optimization supports a subset of CTP scenarios available in the built-in engine.
  • For detailed information on using CTP with each engine, refer to the 'Calculate sales order delivery dates using CTP' guide.

Delivery Alternatives

  • Explore delivery alternatives to meet customer demands.
  • Inventory visibility and on-hand change schedules can help determine the best option.

Monday, 25 September 2023

Journal reports print through X++

Many a time we come across situations where we need to print the journal reports through X++ on some triggers. We have the below simple code through which we can achieve this. 

Sales Invoice journal Print:

SalesInvoiceJournalPrint salesInvoiceJournalPrint;

Set set = new Set(Types::Record);

SRSPrintDestinationSettings srsPrintDestinationSettings;

// Add record

set.add(CustInvoiceJour::findRecId(XXXXX));

set.add(CustInvoiceJour::findRecId(XXXXX));


// Set printer settings

srsPrintDestinationSettings = new SRSPrintDestinationSettings();

srsPrintDestinationSettings.printMediumType(SRSPrintMediumType::Screen);


// Initalize

salesInvoiceJournalPrint = SalesInvoiceJournalPrint::construct();

salesInvoiceJournalPrint.parmPrintFormletter(NoYes::Yes);

salesInvoiceJournalPrint.parmUsePrintManagement(false);

salesInvoiceJournalPrint.parmPrinterSettingsFormLetter(srsPrintDestinationSettings.pack());

// Print

salesInvoiceJournalPrint.printJournal(set);


The similar code can be used for other journal prints as well

Sales:

  • SalesConfirmJournalPrint -
  • SalesPickingListJournalPrint
  • SalesPackingSlipJournalPrint
Purchase:
  • PurchPurchOrderJournalPrint
  • PurchReceiptListJournalPrint
  • PurchPackingSlipJournalPrint
  • PurchInvoiceJournalPrint

Tuesday, 1 August 2023

Certificate issues in D365FO Cloud hosted environment

 The problem with certificates is that they have an expiry date.

Since all Dynamics environments are deployed using LCS and the Cert used is owned by Microsoft we have limited ability to fix the issue on our own. This is why Microsoft built functionality into LCS to help us with this. To fix the issue, just look up the environment in LCS, click Maintain and select Rotate Secrets

The Cert you need to fix is the SSL Certificate

Simply click Rotate SSL Cert and wait for the process to finish. 

Tuesday, 18 July 2023

Move AOT elements between models

In order to move the objects from one model to another model, we opt to copy -paste from original model`s physical folder to destination model`s folder. This is feasible when we have limited objects. but if the object count is more, this approach is tedious.
So here is another way to move the objects from one model to another.
  1. Open the project which has all the objects.
  2. In the same solution, create another project and set its model to the new one .
  3. Drag and drop the objects from the above project to the new one .
  4. Sync and Rebuild.
  5. Now the objects are ready in new model .
This way our job becomes easy and we can be sure the objects are not missed because there are chances of missing the objects when they are moved across physical locations.

Thursday, 8 June 2023

Methods used in AOT Query ranges instead of values

Here is a quick tip, how to add methods in an AOT query ranges instead of values. Refer standard query 'CaseListPage_MyOpenCases'















Similary, In front end forms also we can use methods o filter the data. To do this, the method we use should be part of the class SysQueryRangeUtil. If we do not find a suitable method, we can create a custom method and that can be used globally in D365 FO.

In forms, to filter the value, Use the methods within() in the filtration area as shown in the below example.























In the example, we are trying to filter with created date time value less than 10 days from today. This way, we can set the dynamic values in AOT queries or during report generation and batch job creations parameters to use the recurrence with dynamic ranges.

Friday, 2 June 2023

Encrypted field in D365 FO

Creating an encrypted field in Dynamics 365 Finance and Operations is a simple process that can help secure sensitive information in your application. By using an encryption key to encrypt the data, it ensures that the data remains safe even if it is accessed by unauthorized users.

By encrypted field I mean what you see, for example, in the Email parameters form for the SMTP password:





Encrypted fields

These encrypted fields aren’t stored as plain text in the database, instead they’re encrypted (as its name suggests) using a key and that value is saved.

It’s worth mentioning that each environment has a different encryption key, so when you refresh a sandbox or development environment with data from another environment, the values of encrypted fields are lost because they can’t be unencrypted with a different key.

Creating it

You need a new field in a form, you know that the first step is creating it in a table. For this example, I’ll be adding a field to the CustParameters table and form.

So extend the table in your model and go to the EDTs in the AOT and drag and drop the EncryptedField EDT into the CustParameters table extension. Give it the name you want, I’ll name mine TestEncryptedField, and let’s continue.

Next, you need to create a code extension for the CustParameters table. Because encrypted fields are shown on forms as an edit field, we need a method to encrypt and decrypt the content of the field, and that’s what we’ll do here:

[ExtensionOf(tableStr(CustParameters))]
final class CustParameters_Test_Extension
{
    public edit Name TestEncryptedNameEdit(boolean _set, Name _value)
    {
        return Global::editEncryptedField(this, _value, fieldNum(CustParameters, TestEncryptedField), _set);
    }
}

This is a regular edit method, but it’s calling Global’s editEncryptedField method and there it’s calling Appl’s class EncryptForPurpose and DecryptForPurpose kernel methods that do the job.

Defining an EDT as the return type in the method will help us display the right label in the form, so create your EDTs or use one that fits your purpose. I’m using the Name one because this is just a demo!

Finally, we’ll add a string field in the form and set the CustParameters table as its Data Source property, and the CustParameters_Test_Extension.TestEncryptedNameEdit method as its Data Method property. If your field’s base data type is not a string, you need to add the correct type of new field!

Synchronize, compile and let’s take a look at the field in the UI:










You need to set the form field’s property Password style to Yes! Otherwise, it’ll only show plain text. Let me change that…