NET::ERR_CERT_DATE_INVALID Error in D365 Finance and Operations

Sometimes you receive errors related to invalid or expired certificates in cloud hosted Dynamics 365 finance and operations environments.

Solution:

Solution is quite simple for this error.

Go to LCS and open the environment page

Click on the maintain dropdown and select Rotate secrets option

Click on Rotate SSL certificates

It will take a few minutes to complete this process . Refresh the environment page and, you will no longer receive the invalid certificate error.

Enum values SQL – D365 finance and operation

Enum values in D365 finance and operations stored in a table ‘ENUMIDTABLE’ and ‘ENUMVALUETABLE’. Below is the query to get or verify the enum values

Select eit.NAME,evt.ENUMID,evt.ENUMVALUE, evt.NAME as EnumValueName 
from ENUMIDTABLE eit
inner join ENUMVALUETABLE evt 
on eit.ID= evt.ENUMID
where eit.NAME='TaxDirection'

QR code for the page:

Security privilege access to the user – D365 finance and operations

To check that user has access to specific privilege in d365 finance and operation use below code

    // <summary>
    /// check user has privilige access
    /// </summary>
    /// <param name = "_privilege">privilege identifier as string</param>
    /// <param name = "_userID">UserId</param>
    /// <returns>boolean</returns>
    public static boolean checkUserHasPrivilgeAccess(str _privilege, UserId _userID = curUserId())
    {
        UserInfo userInfo;
        SecurityUserRole securityUserRole;
        SecurityPrivilege securityPrivilege;
        SecurityRolePrivilegeExplodedGraph securityRolePrivilegeExplodedGraph;

        select firstonly RecId, Id, ObjectId, networkDomain from userInfo
            exists join securityUserRole where securityUserRole.User == _userID
            exists join securityRolePrivilegeExplodedGraph 
                where securityRolePrivilegeExplodedGraph.SecurityRole == securityUserRole.SecurityRole
            exists join securityPrivilege 
                where securityPrivilege.RecId == securityRolePrivilegeExplodedGraph.SecurityPrivilege 
                && securityPrivilege.Identifier == _privilege;

        return userInfo.RecId;
    }

You can get privilege identifier from SecurityPrivilege table using privilege name or description

Leave a comment if you have any question.

Copy multiple attachments between different forms with data – Dynamics 365 for Finance and Operations

Scenario:

Sometime a requirement come that we need to copy multiple attachments from one form to another with the flow of data.
For example when purchase order creates from sales order then the attachments also need to be flow from sales order to purchase order

Solution:

First thing first -> Identify the relation between new and existing form(tables).

Then use the below code to achieve this.

I used the onInserted event ,you can use the same or whatever suitable for your scenario. Important thing is record should be created in new table then you can copy the attachment.

    /// <summary>
    ///
    /// </summary>
    /// <param name=”sender”></param>
    /// <param name=”e”></param>
    [DataEventHandler(tableStr(PurchTable), DataEventType::Inserted)]
    public static void PurchTable_onInserted(Common sender, DataEventArgs e)

    {
        DocuRef docuRef;
        PurchTable purchTable = sender;
        SalesTable salesTable = SalesTable::find(purchTable.InterCompanyOriginalSalesId);

        while select docuRef
              where docuRef.RefCompanyId== salesTable.DataAreaId
              && docuRef.RefTableId == salesTable.TableId
              && docuRef.RefRecID == salesTable.RecId
        {

            docuRef.RefTableId = purchTable.TableId;
            docuRef.RefRecId = purchTable.RecId;
            docuRef.insert();
        }
    }

 

//Leave your comments below if you have any query. I will try to help you to solve your problem

Get email subject and body from email template – D365 finance and operations

        SysEmailTable                   sysEmailTable;
        SysEmailMessageTable            sysEmailMessageTable;
        SysEmailContents                sysEmailContents;
        str                             subject, body;
        SysEmailId                      emailTemplateId = 'DlvNote'; //email template name
        LanguageId                      language = 'en-US';
               

        select sysEmailTable
               join sysEmailMessageTable
                where sysEmailMessageTable.EmailId==sysEmailTable.EmailId
                    && sysEmailMessageTable.EmailId== emailTemplateId
                    && sysEmailMessageTable.LanguageId==language;

        subject = SysEmailMessage::stringExpand(sysEmailMessageTable.Subject, mappings); //mappings = placeholders
        body    =  SysEmailMessage::stringExpand(sysEmailMessageTable.Mail, mappings);

Create and send SSRS report as attachment through email (using SysOutgoingEmailTable and Interactive and non-Interactive methodology) – D365 finance and operation

Generate report – In this example we are using delivery note report

Copy the below complete code - CustPacking slip email class contains all the code , Report generation, Email template, email place holders mapping, send email using sysoutgoingemailtable and interactive way email 

/// <summary>
/// Class to send packing slip email
/// </summary>
public class CustPackingSlipEmail
{
    CustPackingSlipJour     custPackingSlipJour;
    Map                     mappings = new Map(Types::String,Types::String);   

    /// <summary>
    /// CustPackingSlipEmail
    /// </summary>
    /// <param name = "_custPackingSlipJour">CustPackingSlipJour</param>
    /// <returns>CustPackingSlipEmail</returns>
    public static CustPackingSlipEmail construct(CustPackingSlipJour _custPackingSlipJour)
    {
        CustPackingSlipEmail CustPackingSlipEmail = new CustPackingSlipEmail();
        custPackingSlipEmail.parmPackingSlip(_custPackingSlipJour);

        return custPackingSlipEmail;
    }

    /// <summary>
    /// CustPackingSlipJour
    /// </summary>
    /// <param name = "_custPackingSlipJour">CustPackingSlipJour</param>
    /// <returns>CustPackingSlipJour</returns>
    public CustPackingSlipJour parmPackingSlip(CustPackingSlipJour _custPackingSlipJour = custPackingSlipJour)
    {
        custPackingSlipJour = _custPackingSlipJour;
        
        return custPackingSlipJour;
    }

    /// <summary>
    /// generateAndSendPackingSlipReport as binary container
    /// </summary>
    /// <param name = "_args">Args</param>
    public void generateAndSendPackingSlipReport(Args _args)
    {
        //Set  variables
        Array                           arrayFiles;
        SRSProxy                        srsProxy;
        Map                             reportParametersMap;
        SRSPrintDestinationSettings     settings;
        Filename                        fileName =     custPackingSlipJour.InternalPackingSlipId + '.pdf';
        SrsReportRunController          formLetterController = SalesPackingSlipController::construct();
        SalesPackingSlipController      controller = formLetterController;
        SalesPackingSlipContract        contract = new SalesPackingSlipContract();
        System.Byte[]                   reportBytes = new System.Byte[0]();
        SRSReportRunService             srsReportRunService = new SrsReportRunService();
        SRSReportExecutionInfo          executionInfo = new SRSReportExecutionInfo();

        Microsoft.Dynamics.AX.Framework.Reporting.Shared.ReportingService.ParameterValue[] parameterValueArray;
        
        //set the report contract parameters
        contract.parmRecordId(custPackingSlipJour.RecId);
        contract.parmTableId(tableNum(CustPackingSlipJour));

        //2nd paramter contract.parm2ndtParameter('2ndParamter value');
        //3rd parameter
        //4th parameter

        //set the report controller parameters
 
        //set report name and design name
        controller.parmArgs(_args);
        controller.parmReportName(PrintMgmtDocType::construct(
                                    PrintMgmtDocumentType::SalesOrderPackingSlip).getDefaultReportFormat());
        controller.parmShowDialog(false);
        controller.parmLoadFromSysLastValue(false);
        controller.parmReportContract().parmRdpContract(contract);

        // Provide printer settings

        settings = controller.parmReportContract().parmPrintSettings();
        settings.printMediumType(SRSPrintMediumType::File);
        settings.fileName(fileName);
        settings.fileFormat(SRSReportFileFormat::PDF);

        // Below is a part of code responsible for rendering the report

        controller.parmReportContract().parmReportServerConfig(SRSConfiguration::getDefaultServerConfiguration());
        controller.parmReportContract().parmReportExecutionInfo(executionInfo);
        srsReportRunService.getReportDataContract(controller.parmreportcontract().parmReportName());
        srsReportRunService.preRunReport(controller.parmreportcontract());
        reportParametersMap = srsReportRunService.createParamMapFromContract(controller.parmReportContract());
        parameterValueArray = SrsReportRunUtil::getParameterValueArray(reportParametersMap);
        srsProxy = SRSProxy::constructWithConfiguration(controller.parmReportContract().parmReportServerConfig());

        // Actual rendering to byte array
        reportBytes = srsproxy.renderReportToByteArray(controller.parmreportcontract().parmreportpath(),
                                                        parameterValueArray,
                                                        settings.fileFormat(),
                                                        settings.deviceinfo());

        // You can also convert the report Bytes into an xpp BinData object if needed
        container binData;
        Binary binaryData;
        System.IO.MemoryStream mstream = new System.IO.MemoryStream(reportBytes);
        binaryData = Binary::constructFromMemoryStream(mstream);

        if (binaryData)
        {
            binData = binaryData.getContainer();
        }

        SysEmailRecipients recipientEmailAddr = SysUserInfo::find(curUserId()).Email;

        //Send email using sysoutgoing email
        this.sendEmailWithAttachment(binData, fileName, recipientEmailAddr);

        //Send email using interactive methodology
        this.sendEmailWithAttachmentInteractive(binData, fileName, recipientEmailAddr);
    }


    /// <summary>
    /// sendEmailWithAttachment using sysoutgoing email table
    /// </summary>
    /// <param name = "_binData">container</param>
    /// <param name = "_fileName">str</param>
    /// <param name = "_recipientEmailAddr">SysEmailRecipients</param>
    public void sendEmailWithAttachment(container _binData, str _fileName, SysEmailRecipients _recipientEmailAddr)
    {
        SysEmailItemId                  nextEmailItemId;
        SysEmailTable                   sysEmailTable;
        SysEmailContents                sysEmailContents;
        SysOutgoingEmailTable           outgoingEmailTable;
        SysOutgoingEmailData            outgoingEmailData;
        str                             subject;
        Filename                        fileExtension = ".pdf";
        
        [sysEmailTable, subject, sysEmailContents] = this.getEmailTemplateDetails();
       
        if (sysEmailTable.RecId > 0)
        {
            nextEmailItemId  = EventInbox::nextEventId();
      
     
            outgoingEmailTable.clear();
            outgoingEmailTable.Origin                       = sysEmailTable.Description;
            outgoingEmailTable.EmailItemId                  = nextEmailItemId;
            outgoingEmailTable.IsSystemEmail                = NoYes::Yes;
            outgoingEmailTable.Sender                       = sysEmailTable.SenderAddr;
            outgoingEmailTable.SenderName                   = sysEmailTable.SenderName;
            outgoingEmailTable.Recipient                    = _recipientEmailAddr;
            outgoingEmailTable.Subject                      = subject;
            outgoingEmailTable.Priority                     = eMailPriority::High;
            outgoingEmailTable.WithRetries                  = NoYes::No;
            outgoingEmailTable.RetryNum                     = 0;
            outgoingEmailTable.UserId                       = curUserId();
            outgoingEmailTable.Status                       = SysEmailStatus::Unsent;
            outgoingEmailTable.Message                      =  sysEmailContents;
            outgoingEmailTable.LatestStatusChangeDateTime   = DateTimeUtil::getSystemDateTime();
            outgoingEmailTable.TemplateId                   = sysEmailTable.EmailId;
            outgoingEmailTable.insert();

            if (conLen(_binData) > 0)
            {
                outgoingEmailData.clear();
                outgoingEmailData.EmailItemId               = nextEmailItemId;
                outgoingEmailData.DataId                    = 1;
                outgoingEmailData.EmailDataType             = SysEmailDataType::Attachment;
                outgoingEmailData.Data                      = _binData;
                outgoingEmailData.FileName                  = _filename;
                outgoingEmailData.FileExtension             = fileExtension;
                outgoingEmailData.insert();
            }
        }
    }

    /// <summary>
    /// send email as interactive or non interactive methodology
    /// </summary>
    /// <param name = "_binData">container</param>
    /// <param name = "_fileName">str</param>
    /// <param name = "_recipientEmailAddr">SysEmailRecipients</param>
    public void sendEmailWithAttachmentInteractive(container _binData, str _fileName, SysEmailRecipients      
                                                     _recipientEmailAddr)
    {  
        System.Byte[]               binData1;
        System.IO.Stream            stream1;
        SysEmailTable               sysEmailTable; 
        SysEmailContents            sysEmailContents;
        str                         subject;
        SysIMailerInteractive       mail;
        SysMailerMessageBuilder     messageBuilder;
        
        Email                       sendFrom = SysUserInfo::find(curUserId()).Email;
        
        [sysEmailTable, subject, sysEmailContents] = this.getEmailTemplateDetails();
                
        // Turn the Bytes into a stream
        for (int i = 0; i < conLen(_binData); i++)
        {
            binData1 = conPeek(_binData,i+1);
            stream1  = new System.IO.MemoryStream(binData1);
        }

        //email sending settings
        mail            = SysMailerFactory::getInteractiveMailer();
        messageBuilder  = new SysMailerMessageBuilder();
        
        messageBuilder.reset()
            .setFrom(sendFrom) // From email address
            .addTo(_recipientEmailAddr) // To Email address
            .setSubject(subject) // Email Subject
            .setBody(sysEmailContents);        //Email Body

        if (stream1 != null)
        {
            //add attachment to the email
            messageBuilder.addAttachment(stream1, _filename);
        }
        
        //send email
        mail.sendInteractive(messageBuilder.getMessage());
    }

    /// <summary>
    /// getEmailTemplateDetails
    /// </summary>
    /// <returns>container</returns>
    private container getEmailTemplateDetails()
    {
        SysEmailTable                   sysEmailTable;
        SysEmailMessageTable            sysEmailMessageTable;
        SysEmailContents                sysEmailContents;
        str                             subject;
        SysEmailId                      emailTemplateId = this.getCustPackingSlipTemplateEmailId();
        LanguageId                      language = 'en-Au';
               
        this.populateEmailMessageMap();

        select sysEmailTable
               join sysEmailMessageTable
                where sysEmailMessageTable.EmailId==sysEmailTable.EmailId
                    && sysEmailMessageTable.EmailId== emailTemplateId
                    && sysEmailMessageTable.LanguageId==language;

        subject = SysEmailMessage::stringExpand(sysEmailMessageTable.Subject, mappings);
        sysEmailContents =  SysEmailMessage::stringExpand(sysEmailMessageTable.Mail, mappings);

        return [sysEmailTable, subject, sysEmailContents];
    }

    /// <summary>
    /// Get Email template
    /// </summary>
    /// <returns>SysEmailId</returns>
    private SysEmailId getCustPackingSlipTemplateEmailId()
    {
        SysEmailId emailId = CustParameters::find().DeliveryNoteEmailId; // new parameter field for email template

        if (!emailId)
        {
            throw error("@Label:DeliveryNoteEmailTemplateError");
        }

        return emailId;
    }

    /// <summary>
    /// populate map for email place holders
    /// </summary>
    private void populateEmailMessageMap()
    {
        SalesTable salesTable = SalesTable::find(custPackingSlipJour.SalesId);

        mappings.insert('DeliveryNoteNumber', custPackingSlipJour.PackingSlipId);
        mappings.insert('Version', custPackingSlipJour.InternalPackingSlipId);
        mappings.insert('SalesOrder', custPackingSlipJour.SalesId ); //strFmt("%1", missingHourTmp.Hour));
        mappings.insert('ProjectID', salesTable.ProjId);
        mappings.insert('CustAccount', custPackingSlipJour.OrderAccount);
        mappings.insert('DeliveryName', custPackingSlipJour.DeliveryName);
        mappings.insert('DeliveryAddress', custPackingSlipJour.deliveryAddress());
        mappings.insert('InvoiceName', custPackingSlipJour.InvoicingName);        
        mappings.insert('InvoiceAddress', custPackingSlipJour.invoicingAddress());
    }
}

Call the above class from the Sales packing slip controller class extension 

[ExtensionOf(classStr(SalesPackingSlipController))]
public final class custSalesPackingSlipController_Extension
{
    /// <summary>
    /// Send delivery note email
    /// </summary>
    /// <param name = "_args">Args</param>
    protected static void doMainJob(Args _args)
    {
        boolean sendMail = false;
        if (Box::yesNo('@Label:SendDeliveryNoteEmail', DialogButton::Yes, 
                         '@Label:SendDLvNoteEmail') == DialogButton::Yes)
        {
            sendMail = true;
        }

        next doMainJob(_args);
       
        if (sendMail)
        {
            CustPackingSlipJour custPackingSlipJour = _args.record();
            CustPackingSlipEmail custPackingSlipEmail = custPackingSlipEmail::construct(custPackingSlipJour);
            custPackingSlipEmail.generateAndSendPackingSlipReport(_args);

            Info('@Label:DlvNoteEmailSent');
        }
    }
}

Package deployment timeout issues (retail retail related errors)- D365 for finance and operations

Scenario:

If you are receiving retail related errors on cloud hosted environments. here is the solution:

Note: Below solution is only applicable if you’re not using the retail functionality at all and you have RDP access of the environment.

Retail server:

If you’re receiving Retail server related error than do the below steps:

Run the DropAllRetailChannelDbObjects.sql and you can find the script in below path K:\DeployablePackages\\RetailServer\Scripts”

This will drop all retail server objects but will be recreated during the update. After running the script, resume the update again.

RetailCloudPos:

RetailStorefront:

If you’re receiving error related to above two and it is timeout error(check in the log file):

Find the step in the runbook and get the script location:

Copy the UpdateCloudPos to the desktop or any other folder as backup

Open the copy file in notepad and clear the script (empty file)

Copy the empty file back to the above folder and replace it.

Same steps you have to do for RetailStorefront.

Resume the package deployment.

D365 apply updates failed – package deployment failed – Dynamics 365 for finance and operations

Issue:

Few times we came across the issue of failing of D365 apply updates or package deployment failed at the step of DevTools.

Resolution:

To resolve the issue follow below steps:

  1. Download the package if not downloaded
  2. Unblock the downloaded package Zip file before extracting
  3. Extract the the package zip file
  4. Navigate to the DevToolsService/Scripts folder in the extracted package folder
  5. Find the the file Microsoft.Dynamics.Framework.Tools.Installer
  1. Double click on the file and install the extension for VS2019

  1. Once extension installation complete resume the package deployment.

Please feel free to comment if you’re facing any issue. We will try our best to help you solve the issues.

D365 Visual studio set default model for new projects

To set default model for new projects in visual studio update the below configuration with your model name

C:\Users\user account\Documents\Visual Studio Dynamics 365Screen Shot 2021-11-23 at 11.24.26 am.png

Edit the file in the notepad and search for default model for new projects node

Screen Shot 2021-11-23 at 11.27.49 am.png

Replace the model name in this case it “Fleet management” with your model name

SSRS – Address in one line in D365, AX – Microsoft Dynamics 365 for Finance and Operations

Issue: Address in the D365 Finance and Operation is not in the single field and thru address method by default it is showing the multiple lines.

Requirement: Show address in one line

Resolution: use below SSRS formula in the text-box where you want to show address in one line below example for Vendor Address

 

=Replace(First(Fields!VendAddress.Value, "PurchPurchaseOrderDS"), Chr(10), ",")

Same can be use for other addresses for example, Customer Address, employee address etc

Send Email with invoice as attachment using Electronic Reporting – Microsoft Dynamics 365 for Finance and Operation

Scenario:

Send Email with invoice as attachment thru electronic reporting

Solution:

Follow the below steps:

  1. Go to Electronic reporting workspace
  2. Click on the Electronic reporting destination

Screen Shot 2020-04-15 at 12.37.06 pm.png

3. Add new record in file destination grid settings type Émail’

Screen Shot 2020-04-15 at 12.38.33 pm.png

4.  Do the settings on the destination screen as below

Screen Shot 2020-04-15 at 12.41.05 pm.png

 

5. On To Field click Edit , click  and select print Management Email

Screen Shot 2020-04-15 at 12.42.43 pm

6. For above settings of Email Source account , click on link button before delete button ,it will open the formula designer , you need to select the field AccountNum (customer account number)

It will select the customer email defined on the customer Master contact details as primary

Screen Shot 2020-04-15 at 12.46.24 pm.png

 

7. click Save and close the formula designer form

8. click on the next two forms and now you can test the email by running the invoice print using print management

 

 

Leave your comments below  if you are facing any issue.

 

To send SSRS report in Email as attachment, please check below link

 

Send email thru code with Report as attachment – Dynamics 365 Finance and Operations

Copy attachments between different forms with data – Dynamics 365 for Finance and Operations

Scenario:

Sometime a requirement come that we need to copy the attachment from one form to another with the flow of data.

For example when purchase order creates from sales order then the attachment also need to be flow from sales order to purchase order

Solution:

First thing first -> Identify the relation between new and existing form(tables).

Then use the below code to achieve this.

I used the onInserted event ,you can use the same or whatever suitable for your scenario. Important thing is record should be created in new table then you can copy the attachment.

  

    /// <summary>
    ///
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    [DataEventHandler(tableStr(PurchTable), DataEventType::Inserted)]
    public static void PurchTable_onInserted(Common sender, DataEventArgs e)
    {
        PurchTable purchTable = sender;
        SalesTable salesTable = SalesTable::find(purchTable.InterCompanyOriginalSalesId);
        DocuRef docuRef = DocuRef::findTableIdRecId(salesTable.DataAreaId, salesTable.TableId, salesTable.RecId);

        if (docuRef)
        {
            docuRef.RefTableId = purchTable.TableId;
            docuRef.RefRecId = purchTable.RecId;
            docuRef.insert();
        }
    }

Leave your comments below if you have any query. I will try to help you to solve your problem

Data Entity Create Virtual Field – Microsoft Dynamics 365 for Finance and Operations

Scenario:
 
Requirement is to have a custom field showing Customer Number and Name.
 
Solution:
 
In that case instead of creating regular field on the Data entity and we will create a virtual field and fill the data at runtime when records are importing
 
Below are the steps needs to perform:
 
 
1. Create extension of the base entity (Example SalesOrderHeaderEntity) or your custom entity
 
2. Open the entity in designer and expand the fields
 
3. Right click and add new field -> StringUnmappedField
 
4. Set the Name property  of new field, in our case I put ‘CustomerNumberAndName’
 
5. Set the IsComputedField Property to No.
 
6. Leave the DataEntityViewMethod Empty
 
7.Use the virtual field to receive the information from outside(odata or excel) and parse the information
 
8. Use chain of command or pre-post event handler if its base entity or customise the method ‘mapEntityToDataSource’
 
‘example of mapEntityToDataSpurce’
 
9. 
public void mapEntityToDataSource(DataEntityRuntimeContext entityCtx, 
                                     DataEntityDataSourceRuntimeContext dataSourceCtx)
{
    next mapEntityToDataSource(entityCtx,dataSourceCtx);

    //Check if desired data source context is available
    switch (_dataSourceCtx.name())
    {
        case dataEntityDataSourceStr(SalesOrderHeaderV2Entity, SalesTable):
        {
            SalesTable salesTable      = _dataSourceCtx.getBuffer();
            this.CustomerNumberAndName = salesTable.InvoiceAccount + ' - ' salesTable.customerName();
        }
        break;
    }
}

10. You can get the value from odata also to use it for different purpose as per request

Business Event Create and Implement – Dynamics 365 For Finance and Operations – X++

Introduction:

Business event introduced in Microsoft Dynamics 365 for Finance and operations to trigger the business process based events and to talk to external systems and by default Microsoft provide some default business(example VendorInvoicePostedBusinessEvent to understand how it works.

Scenario:

Whenever sales invoice is posted then business event should be trigger only in case of specific item. To implement this below is the procedure.

Implementation steps:

3 steps for every business event

1. Build the contract
2. Build the event
3. Code to send the event

Two Classes involves:

Business Event -This class extends the BusinessEventBase , supports constructing the business event, building payload and sending business event

Example of BusinessEvent Class (SalesOrderCreation, update, Delete in that case the BusinessEvent class name should be like SalesOrderCRUDOperation) same goes for Purchase order etc

Business Event Contract – This class extends the BusinessEventsContract class. it defines the payload of business event and allows for population of contract at runtime.

 

 

Implementation :

Example is on Creation of Customer Invoice Transactions return specific item number,name, quantity and amount
Define the contract class
[DataContract]
public final class CustomerInvoiceTransactionItem90Contract extends BusinessEventsContract
{
    private ProdName productName;
    private ItemId itemId;
    private int quantity;
    private amount itemAmount;
    /// <summary>
    /// Initialise method
    /// </summary>
    /// <param name = “_invoiceTrans”> </param>
    private void initialize(CustInvoiceTrans _invoiceTrans)
    {
        CustInvoiceJour custInvoiceJour =                CustInvoiceJour::findFromCustInvoiceTrans(_invoiceTrans.SalesId,_invoiceTrans.InvoiceId,_invoiceTrans.InvoiceDate,_invoiceTrans.numberSequenceGroup);
SalesTable salesTable = SalesTable::find(_invoiceTrans.SalesId);
CustTable custTable = CustTable::find(salesTable.CustAccount);
        // get the variable values
        productName =    EcoResProduct::findByProductNumber(_invoiceTrans.ItemId).productName();
 itemId = _invoiceTrans.itemId;
 quantity = _invoiceTrans.quantity;
 itemAmount = _invoiceTrans.LineAmount;
}
    /// <summary>
    ///
    /// </summary>
    /// <param name = “_invoiceLine”></param>
    /// <returns></returns>
    public static CustomerInvoiceTransactionItem90Contract newFromInvoice(CustInvoiceTrans _invoiceLine)
    {
           CustomerInvoiceTransactionItem90Contract contract = new
                                                                              CustomerInvoiceTransactionItem90Contract();
           contract.initialize(_invoiceLine);
           return contract;
    }
    private void new()
    {
    }
    [DataMember(‘ProductName’), BusinessEventsDataMember(“Product Name”)]
    public ProdName parmProdName(str _productName = productName)
    {
        productName = _productName;
        return productName;
    }
    [DataMember(‘itemId’), BusinessEventsDataMember(“Item Number”)]
    public str parmSerialNumber(str _itemId = itemId)
    {
        itemId = _itemId;
        return itemId;
    }
    [DataMember(‘quantity’), BusinessEventsDataMember(“Quantity”)]
    public str parmLineId(str _quantity = quantity)
    {
        quantity = _quantity;
        return quantity;
    }
    [DataMember(‘itemAmount’), BusinessEventsDataMember(“itemAmount”)]
    public str parmfoPartyType(str _itemAmount = itemAmount)
    {
        itemAmount = _itemAmount;
        return itemAmount;
    }
}
Define the Business Event Class
 [BusinessEvents(classStr(CustomerInvoiceTransactionItem90Contract),
    “Customer Invoice Transaction”,
    “This business event is triggered when an invoice is created.”,
    ModuleAxapta::SalesOrder)]
     public class CustInvoiceTransCreatedBusinessEvent extends BusinessEventsBase
 {
     CustInvoiceTrans custInvoiceTrans;
      private custInvoiceTrans parmInvoiceTrans(CustInvoiceTrans _custInvoiceTrans =              custInvoiceTrans)
     {
         custInvoiceTrans = _custInvoiceTrans;
         return custInvoiceTrans;
     }
     private void new()
     {
     }
     [Wrappable(true), Replaceable(true)]
     public BusinessEventsContract buildContract()
     {
         return      CustomerInvoiceTransactionItem90Contract::newFromInvoice(custInvoiceTrans);
     }
    static public CustInvoiceTransCreatedBusinessEvent    newFromInvoice(CustInvoiceTrans _custInvoiceTrans)
     {
         CustInvoiceTransCreatedBusinessEvent event = new       CustInvoiceTransCreatedBusinessEvent();
        event.parmInvoiceTrans(_custInvoiceTrans);
         return event;
     }
}
Code to invoke the event : below is the code that invoke the business event classes that we define above
 [DataEventHandler(tableStr(CustInvoiceTrans), DataEventType::Inserted)]
    public static void CustInvoiceTrans_onInserted(Common sender, DataEventArgs e)
    {
        CustInvoiceTrans invoiceTrans = sender as CustInvoiceTrans;
        boolean isEvent = BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(CustInvoiceTransCreatedBusinessEvent));
        if (isEvent)
        {
            if(invoiceTrans.itemid==’item90′)
            {
                CustInvoiceTransCreatedBusinessEvent::newFromInvoice(sender).send();
            }
        }
    }
  • After finishing the above code and rebuilding the project then you have to go business event catalogue in the system administration
  • You will find your newly created business event in the list
  • Then from your end point application register the business event , once successfully registered than you will find the end point in your business event catalog Endpoint tab
  • Activate the business event , you are ready to use the newly created business event.

 

Note: Business event can be activated only in 1 legal entity  or all , if you don’t selected any legal entity during activation then it will be activated for all else only for selected legal entity