Thursday, July 12, 2018

Generating Deep Links to open the specific records in D365

The following code is to generate the deep link URL to open the specific records in D365

using Microsoft.Dynamics.AX.Framework.Utilities;

class Dal_URLGeneration
{

    private static str buildAXURL(MenuItemName _menuItemName, MenuItemType _menuItemtype, DataSourceName _dataSource='', FieldName _field='', str _value='' )
    {
        UrlHelper.UrlGenerator generator = new UrlHelper.UrlGenerator();
        System.Uri currentHost = new System.Uri(UrlUtility::getUrl());

        generator.HostUrl = currentHost.GetLeftPart(System.UriPartial::Authority);
        generator.Company = curExt();
        generator.MenuItemName = _menuItemName;
        generator.MenuItemType = _menuItemtype;
        generator.Partition = getCurrentPartition();
        generator.EncryptRequestQuery = true;

        if(_dataSource != '')
        {
            UrlHelper.RequestQueryParameterCollection requestQueryParameterCollection;

            requestQueryParameterCollection = generator.RequestQueryParameterCollection;
            requestQueryParameterCollection.AddRequestQueryParameter(_dataSource, _field, _value);
        }

        System.Uri fullURI = generator.GenerateFullUrl();

        return fullURI.AbsoluteUri;
    }

    public static void main(Args _args)
    {
        str link;

        link = Dal_URLGeneration::buildAXURL(menuItemDisplayStr(CustTable), MenuItemType::Display, formDataSourceStr(CustTable,CustTable), fieldstr(CustTable, AccountNum), "1005" );

        info(link);

    }

}

Note: Change the Property of the display menu item -- Copy caller query --- Yes

Monday, June 25, 2018

Code to create a trade agreement in D365

 PriceDiscTable              priceDiscTable;
 PriceDiscAdmTrans           priceDiscAdmTrans;
 RecordInsertList            priceDiscAdmTransInsertList         = new   RecordInsertList(tableNum(PriceDiscAdmTrans), true);
 PriceDiscAdmTable           priceDiscAdmTable;
 PriceDiscAdmCheckPost       priceDiscAdmCheckPost = new priceDiscAdmCheckPost();     PriceDiscAdmName            PriceDiscAdmName;     

 select PriceDiscAdmName where PriceDiscAdmName.JournalName == "DISC";
 priceDiscAdmTable.clear();
 priceDiscAdmTable.JournalName     = PriceDiscAdmName.JournalName;                 priceDiscAdmTable.Name            = PriceDiscAdmName.Name;                 priceDiscAdmTable.DefaultRelation = PriceDiscAdmName.DefaultRelation;                 priceDiscAdmTable.insert();

priceDiscAdmTrans.clear();
priceDiscAdmTrans.JournalNum    = _priceDiscAdmTable.JournalNum;        priceDiscAdmTrans.ItemCode      = PriceDiscProductCodeType::Table;
priceDiscAdmTrans.ItemRelation  = _inventTable.ItemId;
currencyExchangeHelper = CurrencyExchangeHelper::newExchangeDate(Ledger::current(), systemDateGet());
amountMST = currencyExchangeHelper.calculateCurrencyToCurrency(_currencyCode,Ledger::accountingCurrency(CompanyInfo::current()),_purchasePrice ,true);
priceDiscAdmTrans.Amount        = amountMST;
priceDiscAdmTrans.FromDate      = today();
priceDiscAdmTrans.AccountCode   = PriceDiscPartyCodeType::GroupId;
priceDiscAdmTrans.relation      = PriceType::PricePurch;
priceDiscAdmTrans.AccountRelation   = "ItemGroupId";
priceDiscAdmTrans.Currency      = _currencyCode;
priceDiscAdmTrans.UnitId        = InventTablemodule::find(_inventTable.ItemId,ModuleInventPurchSales::Purch).UnitId;
priceDiscAdmTrans.PriceUnit     = 1;
priceDiscAdmTrans.InventDimId   = _inventTable.defaultInventDim(inventitemordersetuptype::Purch).inventDimId; priceDiscAdmTrans.doInsert();

Creating and revising the Project Budget from Project Forecasts in D365

With the following code we can able to import the project budget and revising too


        MenuItemName                actionName;
        MenuFunction                menuFunction;
        Args                        args = new args();
        IProjBudgetGridUpdatable    projBudgetGridUpdatable;
        ProjBudget                  projBudget,ProjBudgetWFStatus,projBudgetRec;
        ProjBudgetLine              projBudgetLine,PBL;
        projBudgetRevision          projBudgetRevision;
        projBudgetRevisionLine      projBudgetRevisionLine;
        ProjBudgetAllocationLine    projBudgetAllocationLine;
        ForecastModelId             defaultModelIdForForecastImport;
        FormDataSource              projBudget_ds,ProjBudgetLineRevenue_ds,ProjBudgetLineCost_ds;
        ProjBudgetImportBatch       projBudgetImportBatch = new ProjBudgetImportBatch();

       
        args = new Args();
        actionName = menuitemActionStr(projBudgetImportBatch);
   
        ttsbegin;
           
        projbudget::findOrCreateProjectBudget("HH");
        Select forupdate projBudget where projBudget.RootProjId == "HH";
        if(projBudget.BudgetWorkflowStatus == ProjBudgetWorkflowStatus::Created)
        {
           
            projBudgetImportBatch.parmProjId("HH");
            projBudgetImportBatch.parmProjBudgetRecId(projBudget.RecId);
            projBudgetImportBatch.parmSource("CurrentF");
            projBudgetImportBatch.parmMarkValue(0);
            projBudgetImportBatch.parmProjBudgetImportOptions(ProjBudgetImportOptions::Units);
            projBudgetImportBatch.parmProjBaseBudgetOn(projbaseBudgetOn::Forecast);
            projBudgetImportBatch.parmSummarizeByCategory(noyes::Yes);
            projBudgetImportBatch.parmInBatch(noyes::No);
            args.parmObject(projBudgetImportBatch);
            menuFunction = new MenuFunction(actionName, MenuItemType::Action);
            menuFunction.run(args);
            projbudget::updateProjBudgetStatus(projBudget.RecId,ProjBudgetWorkflowStatus::Submitted);
            projbudget::updateProjBudgetStatus(projBudget.RecId,ProjBudgetWorkflowStatus::Approved);
            args.record(projbudget);
            args.parmEnumType(enumnum(ProjBudgetManagerActionType));
            args.parmEnum(ProjBudgetManagerActionType::Commit);
            ProjBudgetManager::main(args);
           
        }
        projBudgetLine.clear();
        projBudgetRec.clear();
       

        // Budget revision
        if(projBudget.BudgetWorkflowStatus == ProjBudgetWorkflowStatus::Approved)
        {
            projBudgetRevision::createRevision(projBudget.RecId);
            select ProjBudgetRevision  where ProjBudgetRevision.ProjBudget == projBudget.RecId;
            projBudgetImportBatch.parmProjId("HH");
            projBudgetImportBatch.parmProjBudgetRecId(projBudget.RecId);
            projBudgetImportBatch.parmProjBudgetRevisionRecId(projBudgetRevision.RecId);
            projBudgetImportBatch.parmSource("CurrentF");
            projBudgetImportBatch.parmMarkValue(0);
            projBudgetImportBatch.parmProjBudgetImportOptions(ProjBudgetImportOptions::Units);
            projBudgetImportBatch.parmProjBaseBudgetOn(projbaseBudgetOn::Forecast);
            projBudgetImportBatch.parmSummarizeByCategory(noyes::Yes);
            projBudgetImportBatch.parmInBatch(noyes::No);
            args.parmObject(projBudgetImportBatch);
            menuFunction = new MenuFunction(actionName, MenuItemType::Action);
            menuFunction.run(args);
            ProjBudgetRevision::updateProjBudgetRevisionStatus(ProjBudgetRevision.RecId,ProjBudgetRevisionWFStatus::Submitted);
            ProjBudgetRevision::updateProjBudgetRevisionStatus(ProjBudgetRevision.RecId,ProjBudgetRevisionWFStatus::Approved);
            args.record(ProjBudgetRevision);
            ProjBudgetRevisionManager::main(args);
            while select forupdate PBL where PBL.ProjId == "HH"
            {
                PBL.UncommittedRevisions =0;
                PBL.update();
           
                while select projBudgetRevisionLine where projBudgetRevisionLine.ProjBudgetRevision == ProjBudgetRevision.RecId
                {
                    select forupdate projBudgetAllocationLine where projBudgetAllocationLine.ProjBudgetLine == PBL.RecId;
                    projBudgetAllocationLine.CommittedRevisions = projBudgetRevisionLine.RevisionAmount;
                    projBudgetAllocationLine.TotalAllocationAmount = projBudgetRevisionLine.NewTotalBudget;
                    projBudgetAllocationLine.update();
                }
            }
        }

Tuesday, June 19, 2018

How to get the TableBuffer from a class of a form in Pre/Post Event handler with chain of command

1. Create an extension class of the parent class

[ExtensionOf(classStr(AMRentTablePost))]
final public class AMRenatTablePost_Extension
{
    public List                RentList;
    public void initFromArgs(Args args)
    {
           
        ;
        Next initFromArgs(args);
        this.parmRentalList(rentalList);
    }

    public List parmRentalList(List _RentalList = RentList)
    {
        RentList = _RentalList;
        return RentList;
    }

}

2. Add that method name where they are getting the table buffer with Next command.
3. Create a parm method in that extension class to get the buffer.
4. In this example we are getting the table buffer in list, else it may be in any format..
5. Create a Pre/Post eventhandler  class to a method of parent table.
6. Get the class buffer like AMRentTablePost                 AMRentTablePost = args.getThis(); 
7. AMRentTable                 localRentTable,amRentTable;
     rentalList                         = AMRentTablePost.parmRentalList();//Add the new parm method of that extensions class
     ListEnumerator               rentals = rentalList.getEnumerator();     
     
     while (rentals.moveNext())
     {
            amRentTable = rentals.current();// Table buffer from the list
         
      }



Sunday, June 17, 2018

How to get the arguments value of method in Pre/Post EventHandler extensions

Here we have taken the Project Quotation Approval Workflow EventHandler class.

Class Name: PSAProjQuotationApprovalEventHandler
Method Name: Completed

 [PostHandlerFor(classStr(PSAProjQuotationApprovalEventHandler), methodStr(PSAProjQuotationApprovalEventHandler, completed))]
    public static void PSAProjQuotationApprovalEventHandler_Post_completed(XppPrePostArgs args)
    {
        WorkflowContext workflowContext;
        PSAProjQuotationApprovalEventHandler            PSAProjQuotationApprovalEventHandler = args.getThis();
        WorkflowElementEventArgs                        _workflowElementeventArgs = args.getArgNum(1);
        workflowContext                                 = _workflowElementEventArgs.parmWorkflowContext();
       
    }

From workflowContext we can write our business logic as we need...



Tuesday, May 29, 2018

Number sequence customization in Dynamics 365

Create a number sequence in a standard module
  • Create new EDT
  • Add a new code block to the loadModule in the NumberSeqModuleXXX class
  • Add a new static method to the parameters table of the module to get the number sequence reference
Using Extension
[ExtensionOf(classStr(NumberSeqModuleCustomer))]
final class NumberSeqModuleCustTest_Extension
{
            protected void loadModule()
            {
                        NumberSeqDatatype datatype = NumberSeqDatatype::construct();
                        next loadModule();                        
datatype.parmDatatypeId(extendedTypeNum(TestId));
datatype.parmReferenceHelp(literalStr('Test ID'));
                        datatype.parmWizardIsContinuous(false);
                        datatype.parmWizardIsManual(NoYes::No);
                       datatype.parmWizardIsChangeDownAllowed(NoYes::No);
                       datatype.parmWizardIsChangeUpAllowed(NoYes::No);
                        datatype.parmSortField(1);                        
datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);
                        this.create(datatype);
            }
}

[ExtensionOf(tableStr(CustParameters))]
final class CustParametersTest_Extension
{
    client server static NumberSequenceReference numRefTestId()
    {
        return NumberSeqReference::findReference(extendedTypeNum(TestId));
    }
}
Create a number sequence in a new module
·        Add a new element to the NumberSeqModule base enum.
·        Create a NumberSeqModule* class for our module.
·        To add a new element to the NumberSeqModule Base Enum we can use an extension.
·        Now we need to create a new class extends with NumberSeqApplicationModule
class NumberSeqModuleTest extends NumberSeqApplicationModule
{
    protected void loadModule()
    {
        NumberSeqDatatype datatype = NumberSeqDatatype::construct();
        datatype.parmDatatypeId(extendedTypeNum(TestId));
        datatype.parmReferenceHelp(literalStr('Test ID'));
        datatype.parmWizardIsContinuous(false);
        datatype.parmWizardIsManual(NoYes::No);
        datatype.parmWizardIsChangeDownAllowed(NoYes::No);
        datatype.parmWizardIsChangeUpAllowed(NoYes::No);
        datatype.parmSortField(1);       
        datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);
        this.create(datatype);
    }

    public NumberSeqModule numberSeqModule()
    {
        return NumberSeqModule::Test;
    }

    [SubscribesTo(classstr(NumberSeqGlobal),delegatestr(NumberSeqGlobal, buildModulesMapDelegate))]
    static void buildModulesMapSubsciber(Map numberSeqModuleNamesMap)
    {
       NumberSeqGlobal::addModuleToMap(classnum(NumberSeqModuleTest), numberSeqModuleNamesMap);
    }
}

Job: (To load all module number sequences)
static void Test_NumSeqLoad(Args _args)
   {
      NumberSeqApplicationModule::loadAll();
   }  

Thursday, April 12, 2018

D365 X++ code to send mail with excel attachment

using OfficeOpenXml;
using OfficeOpenXml.Style;
using OfficeOpenXml.Table;
using System.Net;
using Microsoft.Dynamics.ApplicationPlatform.Services.Instrumentation;
using Microsoft.DynamicsOnline.Infrastructure.Components.SharedServiceUnitStorage;
using Microsoft.Dynamics.ApplicationPlatform.Environment;
using Microsoft.Dynamics.AX.Framework.FileManagement;
class BB_ExcelEmail
{
 
    #define.CurrentVersion(1)
    #localmacro.CurrentList

    #endmacro

    public void run()
    {
        #AviFiles
        SysOperationProgress progress1 = new SysOperationProgress();
 
        int             row=1;
        int             datediff;
        CustAccount     invoiceAccount;
        int             startrow;
        int             col;
        int             i;
        boolean         goin = false;
     
        SysMailerMessageBuilder builder = new SysMailerMessageBuilder();
     
        COM                 Crange;
        COM                 CBorders;
        COM                 CBorder;
        Amount              TotalSales;
        Qty                 TotalQty;
        Amount              IYesterday, Itoday, IOpen;
        Amount              SYesterday, Stoday, SOpen;
        Amount              EYesterday, Etoday, EOpen;
        Amount              invoiceAmount;
        System.IO.StreamReader reader= null;
        System.String contentString;
        System.Net.WebClient webClient;
        DocuFileSaveResult saveResult =DocuFileSaveResult::construct();
         
        System.IO.Stream workbookStream = new System.IO.MemoryStream();
           
        System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
        using (var package = new OfficeOpenXml.ExcelPackage(memoryStream))
        {
            var sheet = package.get_Workbook().get_Worksheets();
            var worksheet = sheet.Add("First sheet");
            var cells = worksheet.get_Cells();
            OfficeOpenXml.Style.ExcelStyle style = cells.get_Item(row,1).get_style();
            OfficeOpenXml.Style.ExcelFont font = style.Font;
            OfficeOpenXml.Style.ExcelColor color = font.Color;
 
            VAR cell = Cells.get_item(row,1);cell.set_value("Exel email test");
            VAR cellStyle = Cells.get_item(row, 1).get_style();
            cellStyle.get_Font().set_Bold(true);
            color.SetColor(System.Drawing.Color::FromArgb(170,0,0));
            font.Size = 20;
            row++;
         
            cell = Cells.get_item(row,1);cell.set_Value("Entry Date");
            cellStyle = Cells.get_item(row, 1).get_style();
            style = cells.style;font  = style.font;color = font.color;
            color.SetColor(System.Drawing.Color::FromArgb(190,0,0));
            cell = Cells.get_item(row,2);cell.set_Value("Sales ID");
            cellStyle = Cells.get_item(row, 2).get_style();
            style = cells.style;font  = style.font;color = font.color;
            color.SetColor(System.Drawing.Color::FromArgb(190,0,0));
            cell = Cells.get_item(row,3);cell.set_Value("Bill To");
            cellStyle = Cells.get_item(row, 3).get_style();
            style = cells.style;font  = style.font;color = font.color;
            color.SetColor(System.Drawing.Color::FromArgb(190,0,0));
            cell = Cells.get_item(row,4);cell.set_Value("End Customer");
            row++;
            package.save();
            downloadUrl = File::SendFileToTempStore(memoryStream, "ExcelEmail.xlsx");
            webClient = new System.Net.WebClient();
            System.IO.Stream        stream = new System.IO.MemoryStream(webClient.DownloadData(downloadUrl));
       

            builder.setFrom(SysEmailParameters::find().SMTPUserName);
            builder.addTo("test@test.com");
            builder.addAttachment(stream,"ExcelEmail.xlsx");
                   
        }
   
        SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(builder.getMessage());
    }

    public static void main(args args)
    {
        BB_ExcelEmail BB_ExcelEmail = new BB_ExcelEmail ();
        ;
             
            BB_ExcelEmail ();
    }

}

Tuesday, March 20, 2018

X++ code to run the report through code and send mail with attachments in D365


SRSPrintDestinationSettings     printerSettings;
Array                           arrayFiles;
System.Byte[]                   reportBytes = new System.Byte[0]();
SRSProxy                        srsProxy;
SRSReportRunService             srsReportRunService = new SrsReportRunService();
Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[]  parameterValueArray;
Map                             reportParametersMap;
SRSReportExecutionInfo          executionInfo = new SRSReportExecutionInfo();


filename = strfmt('%1%2',SSSSSS,'.pdf');
System.IO.Stream workbookStream = new System.IO.MemoryStream();
SysMailerSMTP           mailer = new SysMailerSMTP();
SysMailerMessageBuilder builder = new SysMailerMessageBuilder();
SysEmailParameters      parameters = SysEmailParameters::find();
SrsReportRunController  ssrsController = new SrsReportRunController();
XXXXXXXContract    Contract = new XXXXXXXContract();// define contract class

ssrsController.parmReportName(ssrsReportStr(ReportName, Design));
ssrsController.parmShowDialog(false);
Contract.parmRecordId(YYYY.RecId);//Record recid
ssrsController.parmReportContract().parmRdpContract(Contract);
printerSettings = ssrsController.parmReportContract().parmPrintSettings();
printerSettings.printMediumType(SRSPrintMediumType::File);
printerSettings.fileFormat(SRSReportFileFormat::PDF);
printerSettings.overwriteFile(true);
printerSettings.fileName(filename);
                 
ssrsController.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration());
ssrsController.parmReportContract().parmReportExecutionInfo(executionInfo);
srsReportRunService.getReportDataContract(ssrsController.parmreportcontract().parmReportName());
srsReportRunService.preRunReport(ssrsController.parmreportcontract());
reportParametersMap = srsReportRunService.createParamMapFromContract(ssrsController.parmReportContract());
parameterValueArray = SrsReportRunUtil::getParameterValueArray(reportParametersMap);

srsProxy = SRSProxy::constructWithConfiguration(ssrsController.parmReportContract().parmReportServerConfig());
// Actual rendering to byte array
reportBytes = srsproxy.renderReportToByteArray(ssrsController.parmreportcontract().parmreportpath(),
                                                                      parameterValueArray,
                                                                      printerSettings.fileFormat(),
                                                                      printerSettings.deviceinfo());

builder.setFrom(SysEmailParameters::find().SMTPUserName);
builder.addTo(AAAAAA);
builder.setSubject(strfmt(bbbbbbbb));
builder.setBody(content);
if (reportBytes)
{
     System.IO.Stream            stream         = new System.IO.MemoryStream(reportBytes);
     builder.addAttachment(stream,filename);
}
SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(builder.getMessage());

X++ code to get the individual dimension values from default dimension in D365


public static DimensionDefault  getDefaultDimBranchValues(DimensionValue "",DimensionValue "",DimensionValue "",DimensionValue    "")
{
        DimensionDefault            defaultDimension,result;
        container                   conAttr,conValue;
        str                         dimValue;
        int             counttrans,j;
        DimensionAttribute          dimensionAttribute;
        DimensionAttributeValue     dimensionAttributeValue;
        DimensionAttributeValueSetStorage valueSetStorage        = new DimensionAttributeValueSetStorage();
        conAttr  = ["DimensionName","DimensionName","DimensionName","DimensionName"];
        conValue = [DimensionValue,DimensionValue,DimensionValue,_reDimensionValueorting,DimensionValue];

        for (j = 1; j <= conLen(conAttr); j++)
        {
            dimensionAttribute = dimensionAttribute::findByName(conPeek(conAttr,j));
      
            if (dimensionAttribute.RecId == 0)
            {
                continue;
            }
      
            dimValue = conPeek(conValue,j);
      
            if (dimValue != "")
            {
                dimensionAttributeValue =dimensionAttributeValue::findByDimensionAttributeAndValue(dimensionAttribute,dimValue,false,true);
                valueSetStorage.addItem(dimensionAttributeValue);
            }
        }
        result = valueSetStorage.save();
        return result;
}

X++ code to upload/Save a file in Azure location in D365


using Microsoft.Dynamics.ApplicationPlatform.Services.Instrumentation;
using Microsoft.DynamicsOnline.Infrastructure.Components.SharedServiceUnitStorage;
using Microsoft.Dynamics.AX.Framework.FileManagement;
public class AzureStorage
{
str docfiletype;
    Microsoft.Dynamics.AX.Framework.FileManagement.IDocumentStorageProvider storageProvider; 
    public void uploadfile(Filename _Filename,Filename _filePath)
    {
        guid fileGuid = newGuid();
        str fileId;
        str downloadUrl;
        System.IO.Stream    _stream;
        str fileNameAZ = strFmt('%1/%2', fileId, _fileName);//filename = Filename.Xlsx
        fileId = guid2str(fileGuid);
        _stream = File::UseFileFromURL(_filePath);//filepath = C://Temp//Filename.Xlsx
        var blobInfo = new SharedServiceUnitStorageData();
        blobInfo.Id = fileId;
        blobInfo.Category = "StorageFolder";//Folder name
        blobInfo.Name = fileNameAZ;
        blobInfo.Accessibility = Accessibility::Private;
        blobInfo.Retention = Retention::Permanent;       
        if (_stream.CanSeek)
        {
            _stream.Seek(0, System.IO.SeekOrigin::Begin);
        }
        var blobStorageService = new SharedServiceUnitStorage(SharedServiceUnitStorage::GetDefaultStorageContext());
        blobStorageService.UploadData(blobInfo, _stream);
        var uploadedBlobInfo = blobStorageService.GetData(fileId, "StorageFolder", BlobUrlPermission::Read, System.TimeSpan::FromDays(30));
//Time span for keeping the file at azure location.
        downloadUrl =uploadedBlobInfo.BlobLink;
    }
}