October 03, 2023

X++ code to Enable/Disable the form controls based on User groups in D365FO

 UserGroupList userGroupList;

select firstonly RecId from userGroupList where userGroupList.groupId == VendParameters::find().UserGroupId && userGroupList.userId == curUserId(); this.form().design().showNewButton(userGroupList.RecId ? 1 :0);

September 30, 2023

X++ code to get GST amount in D365 FO

 public Amount getGSTAmount(str type) 

TaxDocumentRowTransaction           taxDocumentRowTransaction; 
TaxDocumentComponentTransaction     taxDocumentComponentTransaction; 
TaxComponentTable_IN                taxcomponent; 
TaxDocumentComponentTransaction_In  taxDocumentComponentTransactionIn; 

select sum(TaxAmount) from taxDocumentComponentTransaction 
exists join taxDocumentRowTransaction 
where taxDocumentRowTransaction.RecId == taxDocumentComponentTransaction.TaxDocumentRowTransactionRecId 
     && taxDocumentRowTransaction.Voucher == this.Voucher  //Voucher number
             && taxDocumentRowTransaction.InvoiceId == this.CustomerInvoiceNo //Invoice number
     && taxDocumentRowTransaction.TransactionDate == this.CustomerInvoiceDate //Invoice date
exists join taxDocumentComponentTransactionIn 
where taxDocumentComponentTransactionIn.TaxDocumentComponnetTransactionRecId == taxDocumentComponentTransaction.RecId 
exists join taxcomponent where taxcomponent.RecId == taxDocumentComponentTransactionIn.TaxComponent 
&& taxcomponent.TaxType == TaxType_IN::GST 
&& taxcomponent.Component == type; 
return TaxDocumentComponentTransaction.TaxAmount; 

September 27, 2023

To Send the email with attachment Using Print Management in D365FO

  [ExtensionOf(classStr(SRSPrintDestinationSettings))]

final class SRSPrintDestinationSettings_Extension

{

    [SubscribesTo(classStr(SRSPrintDestinationSettingsDelegates), delegateStr(SRSPrintDestinationSettingsDelegates, toSendEmail))]

    public static void SRSPrintDestinationSettingsDelegates_toSendEmail(System.Byte[] reportBytes, SrsReportRunPrinter printer, SrsReportDataContract dataContract,Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] paramArray, EventHandlerResult result)

    {

        CustParameters              parameters = CustParameters::find();

        str                                    messageBody;

        SysEmailMessageTable  message;

        LanguageId languageId   =  CompanyInfo::find().LanguageId;

        SRSPrintDestinationSettings printSettings = dataContract.parmPrintSettings();

        SysEmailTable               sysEmailTable = SysEmailTable::find(parameters.EmailTemplate);

        Filename                        fileName;

        SalesConfirmContract   contract = new SalesConfirmContract();

        SalesTable                  salesTable;

        SalesLine                   salesLine;

        CustConfirmJour             custConfirmJour;

        Map                         mappings = new Map(Types::String, Types::String);

        ServiceOrderBatchJobService  service = new ServiceOrderBatchJobService();

        contract = dataContract.parmRdpContract();

        custConfirmJour = CustConfirmJour::findRecId(contract.parmRecordId());

        select firstonly salesTable

            where salesTable.SalesId == custConfirmJour.SalesId;

        select firstonly salesLine

            where salesLine.SalesId == salesTable.SalesId;

        if(!languageId)

        {

            languageId = sysEmailTable.DefaultLanguage;

        }

// Place holders        

mappings = service.placeHolders(salesTable,salesLine,'');

        message     = SysEmailMessageTable::find(sysEmailTable.EmailId, sysEmailTable.DefaultLanguage);

        messageBody = message.Mail;

        messageBody = SysLabel::resolveLabels(messageBody, languageId);

        messageBody = SysEmailMessage::stringExpand(messageBody, SysEmailTable::htmlEncodeParameters(mappings));

        fileName    = SysEmailMessage::stringExpand(printSettings.parmFileName(), SysEmailTable::htmlEncodeParameters(mappings));

        printSettings.parmEMailContract().parmBody(messageBody);

        printSettings.parmFileName(fileName);

    }

}

September 26, 2023

Shrink AxDB SQL transaction log - D365 FO

 ALTER DATABASE AxDB SET RECOVERY SIMPLE;

USE AxDB; GO CHECKPOINT; GO DBCC SHRINKFILE(AxDBCopy_log, 1000); -- 1000 = 1GB GO

Uninstall a package - UAT/Prod - D365 FO

 You might have to uninstall a deployable package. For example, you might be reorganizing your source code. Alternatively, you no longer require an independent software vendor (ISV) product and haven't renewed the license. Therefore, you must remove the package.

A model is a design-time concept that is part of a package. When a model isn't the only model in a module, you can just remove it from the source code. No other steps are required, because when you deploy the updated module, the old module is overwritten. All overlayer models fall into this category. For more information, see Deleting a model.

Prerequisites

  • If any models reference the module that will be removed, the references must be removed from them. For information about how to find the references that must be removed, see Viewing model dependencies.
  • Build and deploy any modules that references were removed from.
  • All references to and from the modules must be removed before you begin to uninstall the module. To remove all a module's references, add a single class to the model. This class should contain no code. It should contain only a reference to the application platform.
  • A Microsoft module cannot be removed. If this is attempted, a validation error will be shown on the package in Lifecycle Services.
  • A module cannot be removed if it is part of the AOT deployable package being installed. If you want to remove a module, be sure that it is not part of the package before adding the name to the ModuleToRemove.txt file.

Uninstall a package

  1. Create a file that is named ModuleToRemove.txt.
  2. In the file, put the name of each module that you want to remove on a separate line. Make sure that you've completed the prerequisites for each module that you're removing.
  3. Create a valid deployable package, and put the ModuleToRemove.txt file in the package\AOSService\Scripts folder.
  4. Upload the package to the Lifecycle Services asset library. Wait for the asset to finish validation, and review any warnings that are shown on the Asset Details panel on the right side of the page.
  5. Install the deployable package. For more information about how to install deployable packages, see Apply updates to cloud environments.
  6. Verify that the package was uninstalled before you complete this procedure in a production environment.

September 20, 2023

Get default site and warehouse of item In D365FO

 static void defaultSite(Args _args)

{ InventTable inventTable = inventTable::find('D0001'); InventItemOrderSetupType setupType = InventItemOrderSetupType::Invent; InventDim inventDim; // Default Site inventDim.InventSiteId = inventTable.inventItemOrderSetupMap( setupType).inventSiteId(inventDim.InventSiteId, inventTable);  // Default Location inventDim.InventLocationId = inventTable.inventItemOrderSetupMap(setupType, InventDim::findOrCreate(inventDim).InventDimId) .inventLocationId(inventDim.InventLocationId, inventTable, inventDim.InventSiteId); inventDim = InventDim::findOrCreate(inventDim); }

September 16, 2023

Setting default values for custom fields - D365 FO

When creating a vendor invoice and you are trying to populate custom fields on table VendInvoiceInfoTable you may find that the following will only work if you are creating a blank invoice and not executing it from the invoice create button on a purchase order

[DataEventHandler(tableStr(VendInvoiceInfoTable), DataEventType::InitializingRecord)] 

public static void VendInvoiceInfoTable_onInitializingRecord(Common sender, DataEventArgs e) 

    VendInvoiceInfoTable vendInvoiceInfoTable = sender as VendInvoiceInfoTable; 

    vendInvoiceInfoTable.CustomField   VendParameters::find().DefaultCustomField; 

 }


This is due to the class PurchFormletterParmDataInvoice.createInvoiceHeaderFromTempTable()
which called .skipEvents(true), skipDataMethods(true), .skipDatabaseLog(true) and calls a query::insert_recordset() because of this none of the default events will get triggered.

In order to properly populate customfields on a blank vendor invoice or creating once from a purchase order the following will need to be done via extensions and CoC.


1.    Add custom fields to VendInvoiceInfoTable

2.    Add custom fields to VendInvoiceInfoTableTmp (name and types need to match what was created on VendInvoiceInfoTable)

1.    We have to add it to this table because on PurchFormLetterParmDataInvoice.insertParmTable() it calls a buf2buf command which loops through the field list.

3.    Create extension class of table VendInvoiceInfoTable and apply a CoC of defaultRow method which will populate the value onto both the regular and tmp instance of VendInvoiceInfoTable however it will not save to the database unless the remaining steps are completed

/// <summary>

/// Default values for a vendor invoice header from a purchase order

/// </summary>

[ExtensionOf(tableStr(VendInvoiceInfoTable))]

final class InvoiceModsVendInvoiceInfoTable_Extension

{

    /// <summary>

    /// COC table method defaultRow which resets default valies

    /// </summary>

    /// <param name = "_purchTable">PurchTable</param>

    /// <param name = "_ledgerJournalTrans">LedgerJournalTrans</param>

    /// <param name = "_resetFieldState">Reset field state</param>

    public void defaultRow(PurchTable _purchTable, LedgerJournalTrans _ledgerJournalTrans, boolean _resetFieldState)

    {

        CustomEDTType defaultCustomField;

        

 next defaultRow(_purchTable,_ledgerJournalTrans,_resetFieldState);

 

        //find the default custom field from vend parms

 defaultCustomField = VendParameters::find().DefaultCustomField;

        

 //save the default invoice type to the header which will get copied to    VendInvoiceInfoTableTmp and then back to the main table due to PurchFormLetterParmDataInvoice.createInvoiceHeaderFromTempTable

 this.CustomField = defaultCustomField;

 

    }

 

}

4.    Create extension class of PurchFormLletterParmDataInvoice and apply a CoC to buildCreateInvoiceHeaderFromTempTableFieldQuery and buildCreateInvoiceHeaderFromTempTableFieldMap because the method PurchFormletterParmDataInvoice.createInvoiceHeaderFromTempTable() creates a dynamic map of the fields to copy from the temp table into the main table 

[ExtensionOf(classStr(PurchFormletterParmDataInvoice))]

final class InvoiceModsPurchFormletterParmDataInvoice_Extension

{

    /// <summary>

    /// COC method that adds our custom field to the Field Query selection  from the temp table

    /// </summary>

    /// <param name = "_qbdsVendInvoiceInfoTableTmp">VendInvoiceInfoTableTmp</param>

    protected void buildCreateInvoiceHeaderFromTempTableFieldQuery(QueryBuildDataSource _qbdsVendInvoiceInfoTableTmp)

    {

        next buildCreateInvoiceHeaderFromTempTableFieldQuery(_qbdsVendInvoiceInfoTableTmp);

 

        //add custom selection field

 _qbdsVendInvoiceInfoTableTmp.addSelectionField(fieldNum(VendInvoiceInfoTableTmp, CustomField));

    }

 

    /// <summary>

    /// COC method thats adds our custom field to the dynamic field map against the main table. Which will get copied     from the selection query

    /// </summary>

    /// <param name = "_qbdsVendInvoiceInfoTableTmp">VendInvoiceInfoTableTmp</param>

    /// <returns>Modified dynamic map to insert into the db</returns>

    protected Map buildCreateInvoiceHeaderFromTempTableFieldMap(QueryBuildDataSource _qbdsVendInvoiceInfoTableTmp)

    {

        var targetToSourceMap = next buildCreateInvoiceHeaderFromTempTableFieldMap(_qbdsVendInvoiceInfoTableTmp);

 

        targetToSourceMap.insert(fieldStr(VendInvoiceInfoTable, CustomField), [_qbdsVendInvoiceInfoTableTmp.uniqueId(), fieldStr(VendInvoiceInfoTableTmp, CustomField)]);

       

 return targetToSourceMap;

     }

 

}

By applying our populate method to the defaultRow() method this will also trigger the value to populated on a blank vendor invoice once a vendor account is selected.