Showing posts with label d365. Show all posts
Showing posts with label d365. Show all posts

Wednesday, 9 December 2020

Vendor in Supply Chain Management Dynamics 365

Vendor collaboration

The following image illustrates typical processes between a company and a vendor that would use the Vendor collaboration features in Supply Chain Management.

  Vendor in Supply Chain Management Dynamics 365,vendor in Dynamics 365 finance and operations,D365

The above content is taken from : https://docs.microsoft.com/

inventory management in D365

 Inventory management and Warehouse management

Inventory management

You can use the Inventory management and Warehouse management modules to perform the following tasks:

  • Inbound operations
  • Quality assurance
  • Warehouse operations
  • Outbound operations
  • Inventory control
The above content is taken from : https://docs.microsoft.com/

Wednesday, 6 May 2020

BP error 'parameter not used' d365 AX

BP error 'parameter not used' d365 AX 

Add the below text at the end with comma
,SuppressBPWarning('BPParameterNotUsed', "Parameter required"  - to end of the decorator.

E.g.
   [FormDataFieldEventHandler(formDataFieldStr(aForm, aDatasource, aField), FormDataFieldEventType::Validating),SuppressBPWarning('BPParameterNotUsed', "Parameter required")
]

Thursday, 23 January 2020

CONTRACT CLASS IN SYSOPERATION D365 CODE X++ DYNAMICS AX

Hi,
In the below post you will see the sysoperation framework contract class which can be used to run the class form the contract class.

/// <summary>
///myclass contract
/// </summary>
[DataContractAttribute]
class MyClassContract
{
    str                      packedQuery;
    ItemId itemid;
    InventLocationId locationid;
    InventSiteId siteId;
    InventQty qty;

    [DataMemberAttribute,
    AifQueryTypeAttribute('_packedQuery', querystr(MyClassQuery))
    ]
    public str parmQuery(str _packedQuery = packedQuery)
    {
        packedQuery = _packedQuery;
        return packedQuery;
    }

    public Query getQuery()
    {
        return new Query(SysOperationHelper::base64Decode(packedQuery));
    }

    public void setQuery(Query _query)
    {
        packedQuery = SysOperationHelper::base64Encode(_query.pack());
    }

    [DataMemberAttribute,  SysOperationControlVisibilityAttribute(false)]
    public ItemId parmItemid(ItemId _itemid = itemId)
    {
        itemid = _itemid;
        return itemid;
    }

    [DataMemberAttribute,  SysOperationControlVisibilityAttribute(false)]
    public InventSiteId parmSiteId(InventSiteId _siteId = siteId)
    {
        siteId = _siteId;
        return siteId;
    }

    [DataMemberAttribute,  SysOperationControlVisibilityAttribute(false)]
    public InventlocationId parmLocationId(InventlocationId _locationid = locationid)
    {
        locationid = _locationid;
        return locationid;
    }

}

********************************************************************************
for validation use below class
/// <summary>
/// desctiption
/// </summary>
[DataContractAttribute]
public class MyClassContract implements SysOperationValidatable
{
    str         query;
    TransDate   fromDate;
    TransDate   toDate;
    DataAreaId fromDateany,toDateany;
 
   [
        DataMemberAttribute,
        SysOperationLabelAttribute('@Label'),
        SysOperationDisplayOrderAttribute('1')
    ]
    public TransDate parmFromDate(TransDate _FromDate = FromDate)
    {
        FromDate = _FromDate;
        return FromDate;
    }
 
    [
        DataMemberAttribute,
        SysOperationLabelAttribute('@Label'),
        SysOperationDisplayOrderAttribute('2')
    ]
    public TransDate parmToDate(TransDate _toDate = toDate)
    {
        toDate = _toDate;
        return toDate;
    }

    [DataMemberAttribute, AifQueryTypeAttribute('_query', querystr(MyClassQuery))]
    public str parmQuery(str _query = query)
    {
        query = _query;
        return query;
    }

    public Query getQuery()
    {
        return new Query(SysOperationHelper::base64Decode(query));
    }

    public void setQuery(Query _query)
    {
        query = SysOperationHelper::base64Encode(_query.pack());
    }

    public static MyClassContract construct()
    {
        return new MyClassContract();
    }

    public boolean validate()
    {
        boolean ret = true;

        if (!this.parmFromDate() || !this.parmToDate())
        {
            ret = checkFailed("@@Label");
      }

        return ret;
    }

    protected void new()
    {
    }

}

Thanks!!!!!!!!!!!!!!!!11111

Controller class for SysoperatonFramework D365 Dynamics AX

Hi,
In the below post you will see the sysoperation framework controller class which can be used to run the class form the controller class.

[SysOperationJournaledParametersAttribute(true)]
class MyclassController extends SysOperationServiceController
{
    public static void main(Args args)
    {
        MyclassController controller;
        controller = MyclassController::newFromArgs(args);
     
        controller.startOperation();
    }
    public void new()
    {
        super();
   
        this.parmClassName(classStr(MyclassService));
        this.parmMethodName(methodStr(MyclassService, processClassMethod));
        this.parmExecutionMode(SysOperationExecutionMode::Synchronous);
        this.parmDialogCaption("@Label");
    }

    public ClassDescription caption()
    {
        return "@Label";
    }

    public static MyclassController  newFromArgs(Args _args)
    {
        MyclassController    controller;
           
        controller = new MyclassController();
        controller.initializeFromArgs(_args);
        return controller;
    }
}

Tuesday, 5 November 2019

how to add range the query of the contract class in D365 code.

how to add range the query of the contract class in D365 code.

 private void initQuery(Contractclass _contract)
    {
        query   = _contract.getQuery();
        wmsQBDS = query.dataSourceTable(tableNum(inventtable));

        QueryBuildRange      errorRange = wmsQBDS.addRange(fieldNum(inventtable, Isopen));

        errorRange.value(queryValue(NoYes::No));
        errorRange.status(RangeStatus::Locked);

        QueryBuildDataSource QBDS =

       QBDS.addDataSource(tableNum(NewTable));
        wmsHeaderQBDS.relations(true);
        wmsHeaderQBDS.joinMode(JoinMode::ExistsJoin);
        SysQuery::findOrCreateRange(wmsHeaderQBDS, fieldNum(NewTable, Newfield)).value('newrange');
     
    }
Please note that NewTable needs to have a relation with the InventTable or else you will also need to add a new relation.

Thanks,
Vikas Mehta.

Tuesday, 22 October 2019

how to write validateField method in Dynamics AX, d365

validateField method in Dynamics AX, d365

 public boolean validateField(FieldId _fieldIdToCheck)
    {
        boolean ret;

        ret = super(_fieldIdToCheck);

        switch(_fieldIdToCheck)
        {
            case fieldNum(InventTable, HSNCodeTable_IN) :
                  if (this.HSNCodeTable_IN)
                {
                    ret = ret && checkFailed("@TaxGST:LabelCheck");
                }
                break;
        }
        return ret;
    }


Below is an event handler of validate field in D365
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
[DataEventHandler(tableStr(InventTable), DataEventType::ValidatedField)]
public static void InventTable_onValidatedField(Common sender, DataEventArgs e)
{     
                ValidateFieldEventArgs event = e as ValidateEventArgs;
                InventTable InventTable= sender as InventTable;
                //do anything
}

Similarly we can have Posthandler for salesline or inventtable as an example.

[PostHandlerFor(tableStr(SalesLine), tableMethodStr(SalesLine, validateField))]
    public static void SalesLine_Post_validateField(XppPrePostArgs args)
    {
        SalesLine salesLine = args.getThis();
        FieldId fieldId = args.getArg("_fieldId");
        boolean ret = args.getReturnValue();

        switch(fieldId)
        {
            case fieldNum(SalesLine, LinePercent):
                if (salesLine.LinePercent > 100)
                {
                    ret = ret && checkFailed("Wrong");
                }
                break;
        }

        args.setReturnValue(ret);
    }

Thanks,
Vikas Mehta.

how to get original value of a table in Dynamics D365 ,ax 2012

how to get original record of a table in Dynamics D365 ,ax 2012

Hi all,
So in order to get the original record while updating any record in a table you will need the original/previously unchanged record to compare in some scenarios.
In that case you can use the below code as shown.

    public void update()
    {
        InventTable     this_Orig           = this.orig();
      
        ttsbegin;

       super();

      
        if (this_Orig.SalesModel                       != this.SalesModel              ||
            this_Orig.SalesPriceModelBasic      != this.SalesPriceModelBasic    ||
            this_Orig.SalesContributionRatio    != this.SalesContributionRatio  ||
            this_Orig.SalesPercentMarkup        != this.SalesPercentMarkup)
        {
            InventTable::updateAutoSalesPrice(this.ItemId);
        }
        ttscommit;
    }
thanks,
Vikas Mehta.

Monday, 21 October 2019

TRY CATCH CODE IN DYNAMICS AX ,D365 ,AX 2012 CODE

TRY CATCH CODE IN DYNAMICS AX ,D365 ,AX 2012 CODE

System.Exception ex;
   try
   {
       FormletterService.Run()      
   }
   catch(Exception::CLRError)
   {
       ex = ClrInterop::getLastException();
        if (ex != null)
        {
           ex = ex.get_InnerException();
           if (ex != null)
           {
               throw error(ex.ToString());
           }
    }

}

Thanks,
Vikas Mehta.  

HOW TO GET GRID RECORDS IN DYNAMICS AX

HOW TO GET ALL THE GRID RECORDS IN DYNAMICS AX 

If you want to get the records of all the selected records in the grid on a form then write the below code in the clicked method of the form,
we can loop it for multiple records and can do any task required.

for (custInvoiceJourLoc = getFirstSelection(custInvoiceJour_ds);
custInvoiceJourLoc;
custInvoiceJourLoc = custInvoiceJour_ds.getNext())
{
// do some tasks here.

}

Thanks,
Vikas Mehta.

HOW TO GET DIMENSION FROM A RECORD

HOW TO GET DIMENSION FROM A RECORD

static void getCustomerDimension(Args _args)
{
    CustTable                         custTable = CustTable::find("Cust001");
    DimensionAttributeValueSetStorage dimStorage;
    Counter i;
      
    dimStorage = DimensionAttributeValueSetStorage::find(custTable.DefaultDimension);
  
    for (i=1 ; i<= dimStorage.elements() ; i++)
    {
        info(strFmt("%1 = %2", DimensionAttribute::find(dimStorage.getAttributeByIndex(i)).Name,        
                               dimStorage.getDisplayValueByIndex(i))); 
    }

}    

Thanks,
Vikas

Open form from Infolog Dynamics Ax 2012 Open form on message click

Dynamics Ax 2012 Open form from Infolog  
Open form on message click

SysInfoAction_FormRun    infoAction = SysInfoAction_FormRun::newFormName(formStr(CustTable));

infoAction.parmDescription("Open form Customer Details");
infoAction.parmCallerBuffer(CustTable); // automatic dynalink
info("Purchase invoice contains VAT IN. Please record TAX Invoice Number in ID Localization module after this.", "", infoAction);

Thanks,
Vikas Mehta.

Saturday, 12 October 2019

how to get all datasource in form event handlers in dynamics d365

how to get all datasource in form event handlers in dynamics d365

[FormEventHandler(formStr(HcmWorkerPositions), FormEventType::Closing)]
    public static void HcmWorkerPositions_OnClosing(xFormRun sender, FormEventArgs e)
    {
        FormRun         element = sender;
        FormRun         formrun;
        FormDataSource  formDatasource;
        int             idx;
        str             name;

        formrun = element.args().caller();

        name = element.args().callerName();
//sender.dataSource(formDataSourceStr(HcmWorkerPositions, hcmWorker)); you can also try this.
        if(formrun && name == 'hcmWorker')//hcmworker is second datasource.
        {           
            for(idx=1;formrun.dataSourceCount();idx++)
            {
                if(formrun.dataSource(idx).cursor() is HcmEmploymentDetail)
                {
                    formDatasource = formrun.dataSource(idx);
                    formDatasource.research(true);
                    break;
                }
            }
        }
    }

Friday, 11 October 2019

BP Error 'parameter not used' fix

BP Error 'parameter not used' fix

Many times you come across the error after compiling.
The best solution is to remove the parameter in case it is not required because if it is not used then why declare it.
However in many cases while extension you need the paramtere and hence if you want to supress this error then you can use the following code ..place it above the method within the attiributes and you wont get the error.

SuppressBPWarning('BPParameterNotUsed', "Parameter required" 
[FormDataFieldEventHandler(formDataFieldStr(SalesForm, Datasource, Field), FormDataFieldEventType::Validating),SuppressBPWarning('BPParameterNotUsed', "Parameter required")
]
{
///code here
}

Thanks,
Vikas Mehta.

D365 try catch how to get exact error message


HOW TO GET ERROR MESSAGE IN TRY CATCH


System.Exception exception;
try
{

}
catch(Exception::CLRError)
{
exception = CLRInterop::getLastException();
while(exception)
{
error( exception.get_Message() );
exception = exception.get_InnerException();
}
throw Exception::Error;
}

NOTE: Code inside the catch statement will only get executed of the tts level is zero.
Thanks,
Vikas Mehta

Wednesday, 9 October 2019

Code to change to Accounting currency in D365 Dynamics ax


Code to change to Accounting currency in D365 Dynamics ax 

Currency::amount(markupTrans.Value, markupTrans.CurrencyCode);

In the above code you can use any other table having corresponding values eg.salestrans.

Thanks,
Vikas Mehta.

CREATE AND POST PRODUCTION ROUTE JOURNAL USING PRODUCTION ORDER

CREATE AND PRODUCTION ROUTE JOURNAL USING PRODUCTION ORDER

static void createRouteCardJournalSample(Args _args)
{
    ProdJournalTable                      prodJournalTable;
    ProdJournalRoute                     prodJournalRoute;
    ProdRoute                               prodRoute;
    ProdId                                     prodId     = 'PO001';
    OprNum                                  oprNum   = 20;
    RouteOprId                              routeOprId;
    ProdJournalCheckPostRoute     prodJournalCheckPostRoute;

    select firstonly prodRoute
                where prodRoute.ProdId == prodId  && prodRoute.OprNum == oprNum;

    prodJournalTable.clear();
    prodJournalTable.initValue();
    prodJournalTable.JournalType            = prodjournaltype::RouteCard;
    prodJournalTable.ProdId                     = prodId;
    prodJournalTable.JournalNameId       = ProdParametersDim::findDefault().RouteJournalNameId;
    prodJournalTable.Description             =                                                  ProdJournalName::find(prodJournalTable.JournalNameId).Description;
    prodJournalTable.VoucherSeqRecId   = ProdJournalName::find(prodJournalTable.JournalNameId).VoucherSeqRecId;
    prodJournalTable.VoucherDraw        = journalVoucherDraw::Post;
    prodJournalTable.NumOfLines         = 1;
    prodJournalTable.insert();

    //Route card entry
    prodJournalRoute.clear();
    prodJournalRoute.JournalId               = prodJournalTable.journalId;
    prodJournalRoute.ProdId                   = prodId;
    prodJournalRoute.initValue();
    prodJournalRoute.OprNum               = oprNum;
    prodJournalRoute.OprId                    = prodRoute.OprId;
    prodJournalRoute.JobType                = RouteJobType::Process;
    prodJournalRoute.CategoryHoursId  = prodRoute.SetUpCategoryId;
    prodJournalRoute.CategoryQtyId      = prodRoute.ProcessCategoryId;
    prodJournalRoute.DefaultDimension = prodRoute.DefaultDimension;
    prodJournalRoute.WrkCtrId               = prodRoute.WrkCtrIdCost;
    prodJournalRoute.QtyGood               = 2;
    prodJournalRoute.Hours                    = 1;
    prodJournalRoute.insert();
    info(prodJournalTable.JournalId);
 
    ProdJournalCheckPostRoute = ProdJournalCheckPostRoute::newPostJournal(prodJournalRoute.journalId,true);
    ProdJournalCheckPostRoute.run();
}

Thursday, 24 January 2019

DELETE ACTIONS with examples and explanation in d365

DELETE ACTIONS
  1.  None
  2. Cascade
  3. Restricted
  4. Cascade+Restricted.
A.            None
              Cascade
              Restricted
              Cascade+Restricted.

To maintain data integrity we will use delete actions 
Delete actions will come in to picture when user is trying to delete a record [Alt + f9]

Cascade: Setting the DeleteAction property to Cascade extends the functionality of the table's delete method. As a result, super(), in delete, initiates a cascaded deletion, propagating the delete from table to table.

A cascaded delete is implicitly protected by tts. Database changes aren't committed until the entire transaction is complete.

This cascading will take place whether the deletion is performed in code or directly by a user through the user interface.

Ex: On the CustTable table, a cascading delete action has been defined for the CustBankAccount table. When a customer is deleted from the CustTable table, the delete method also ensures that the corresponding bank account information is automatically deleted.
Restricted: While deleting a record, If the record having any transcations then a warning message will appear. If the record is not having any transactions in another table then only deleted.

Restricted
Setting the DeleteAction property to Restricted extends the functionality of the table's validateDelete method.

As a result, super(), in validateDelete, checks whether records exist on related tables. If records do exist, validateDelete returns false. The forms system ensures that the deletion is not performed. In your own X++ code, check the return value of validateDelete. Don't delete the primary or related records if the method returns false.

Ex:On the CustTable table, a restricted delete action has been defined for the CustTrans table. When a customer is deleted in the CustTable table, the validateDelete method ascertains whether transactions exist for the customer in the CustTrans table. If so, validateDelete returns false.

Cascade + Restricted: Setting the DeleteAction property to Cascade+Restricted extends the functionality of the table's validateDelete and delete methods.

As a result, super(), in validateDelete, ascertains whether records exist on related tables. Whether deleting records from forms or X++, if validateDelete returns false, the primary record isn't deleted and the cascading delete isn't performed. You should first delete the records in the related table before deleting the primary record.

If the primary record is being deleted as part of a cascading delete, the primary record and the records in the related table will be deleted.
Reference

Ex.The Cascade+Restricted delete action is used in the standard application for LedgerJournalTrans on LedgerJournalTable. This type of delete action is useful when you prefer a total clean-up—when you delete a customer, you also delete all the transactions associated with that customer.
 e.g.: tableA (Customer) (a cascade deleteaction to tableB) tableB (SalesOrder) (a cascade+restricted deleteaction to tableC) tableC (SalesLine)

When a record of tableB will be deleted, the restricted part of the deleteaction will be performed. The record of tableB can only be deleted, if no record in tableC exist for the record in tableB. (The SalesOrder can only be deleted, if no SalesLine exist for the SalesOrder).


A record in tableA will be deleted, so the cascade deleteaction to tableB will be performed. In this case, the cascade part of the deleteaction to tableC will be performed. (When a Customer will be deleted, the SalesOrders and SalesLines will also be deleted)

None - nothing
Cascade - both tables are deleted via code and front end.
Restricted - via form -> error , if you try to delete via code only second table will get deleted.In case you use validatedelete() then you will get errror.
C+R : in both cases both deleted. No error is raised (diff) 

Wednesday, 23 January 2019

What are entities in d365 ? HOW TO CREATE ENTITY IN D365 ?

What are entities in d365 how to you create entity in d365 

ax 7, d365, d365 finance and operations, Interview questions, What are entities in d365 how to you create entity in d365,
Below is a simple example

The entities are used to model and manage business data in Dynamics 365 for Customer Engagement apps. For example, entities such as account, campaign, and incident (case) can be used to track and support sales, marketing, and service activities. An entity has a set of attributes and each attribute represents a data item of a particular type. For example, the account entity has Name, Address, and OwnerId attributes. Conceptually, an entity is like a database table, and the entity attributes correspond to the table columns. Creating an entity record (or, simply a record) in Dynamics 365 for Customer Engagement apps is like adding a row in a database table. The entities are divided into three categories: system, business, and custom. As a developer working with business data, you will use business and custom entities. System entities are used by Dynamics 365 for Customer Engagement apps to handle all internal processes, such as workflows and asynchronous jobs. You cannot delete or customize system entities

FMLabCustomer entity

Create a data entity for FMLabCustomer in the Fleet Management model. This entity will be used to manage master data through import/export and integration services. The primary data source is FMCustomer, and the secondary data source is FMAddressTable.

Data entity

FMLabCustomerEntity

Data entity fields

NameMapping
CellPhoneFMCustomer.CellPhone
DriverLicenseFMCustomer.DriverLicense
EmailFMCustomer.Email
FirstNameFMCustomer.FirstName
LastNameFMCustomer.LastName
CustomerGroupFMCustomer.CustGroup
AddressLine1FMAddressTable.AddressLine1
AddressLine2FMAddressTable.AddressLine2
CityFMAddressTable.City
StateFMAddressTable.State
ZipCodeFMAddressTable.ZipCode
CountryFMAddressTable.Country

Corresponding staging table

Staging tables are used in import/export scenarios to provide intermediary storage during file parsing and transformation. These tables are also used in connector integration scenarios. In many cases, staging table are mapped 1:1 to an entity. The staging table that corresponds to the FMLabCustomerEntity entity is named FMLabCustomerStaging.

Create a new project

  1. In Visual Studio click File > New > Project, and then select Finance and Operations Project.
  2. Right-click the project, click Properties, and verify that the project is in the Fleet Management model. If it isn't, set the Model property to Fleet Management.

Add a new data entity to your project

  1. Create a new entity that is named FMLabCustomerEntity. Right-click you project, and then click Add > New item. The Add New Item dialog box opens.
  2. Select Data Entity, and then set the Name property to FMLabCustomerEntity.
  3. Click Add.
  4. In the Data entity wizard, specify the properties for the data entity that you're creating. Use the values that are shown in the following screen shot.
     Note
    The name of an entity must not have '_' or any numeric digits (0…9). Using these characters may result in mapping errors later.
    Data Entity Wizard
  5. Click Next. For more information about the function of each property, see "Categories of entities" and "Building an entity" in Data entities.
  6. Add fields to the new entity from your data source, as shown in the following screen shot. You can add fields from the primary data source, FMCustomer. For this entity, clear the check box for the Image and LicenseImage container types to simplify testing.
  7. Rename the data entity fields to reflect public data contract standards, or click Convert labels to field names to generate names from the existing labels.
  8. On the line for the DriverLicense field, select the Is mandatory check box. This field will be used as the natural key for the entity.
    Data Entity Wizard 2
  9. In the Data source field, select PrimaryAddress. Notice that the PrimaryAddress data source is automatically added because of automatic expansion or the surrogate foreign key replacement of AddressID.
    Steps and add fields
  10. Select the fields from the PrimaryAddress data source that you want to be part of your entity. Additionally, rename the following fields to reflect proper public data contract naming:
    • PrimaryAddress _AddressLine1 > AddressLine1
    • PrimaryAddress _AddressLine2 > AddressLine2
    • PrimaryAddress _City > City
    • PrimaryAddress _State > State
    • PrimaryAddress _ZipCode > ZipCode
    • PrimaryAddress _Country > Country
    Data entity wizard
  11. Click Finish. A data entity item and staging table are added to the project.
    Solution explorer

Build your project

  1. In Solution Explorer, right-click your project, and then click Properties.
  2. Change the value of the Synchronize database on build property to True, and then click OK. This property must be set only one time per project.
     Note
    Entities are created as views in Microsoft SQL Server, and staging tables are also added. Therefore, you must sync a database when you build entities.
    Property pages
  3. On the Visual Studio toolbar, click Build > Build Solution to build the project.
  4. Verify that the build doesn't contain any errors. At this point in the tutorial, warnings are allowed.

Visually validate and customize an entity

  1. In Solution Explorer, right-click the FMLabCustomerEntity node, and then click Open. The designer for the entity opens in the middle pane.
  2. Validate the properties of the FMLabCustomerEntity entity. Select the entity in Solution Explorer, and compare the Properties pane values to the following screen shot.
  3. Set the Label property to Fleet Lab Customers.
    FMLabCustomerEntity - Properties
  4. In the left pane, click Data Sources > FMCustomer > Data Sources > FMAddressTable.
  5. Change the Is Read Only property to No. This is a known issue. Eventually, the value will be set to Yes or No automatically, based on the type of join. The value should be Yes for composition scenarios, and No for associations (surrogate foreign key expansions). This property enables the data source to be read/write.
    FMLabCustomerEntity - Properties2
  6. In the FMLabCustomerEntity designer, click Keys > EntityKey, and then expand the Fields node. Verify that the list of fields matches the following screen shot.
    FMLabCustomerEntity
  7. To visually validate the staging table that will be used for import/export, open the FMLabCustomerStaging table in the designer, and then select the FMLabCustomerStaging node.
    fMLabCustomerStaging - Properties
  8. Click FMLabCustomerStaging > Fields. In the following screen shot, the standard fields of the staging tables are selected. All entity staging tables have these standard fields. The screen shot also shows the data fields that belong on this data entity.
    FMLabCustomerStaging
  9. In Solution Explorer, right-click your project, and then select Rebuild to rebuild and synchronize the project.

Testing data entities

Entities can be tested by using various methods in X++, through data import/export, or through integrations. In this section, we'll explore scenarios for validating entities.

Test the entity by using X++ code

One of the most common ways of interacting with data entities is through X++, by using a unit test or a runnable job to validate that the entities have been built. In this example, we will use a runnable job.
  1. In Solution Explorer, click Add > New item > Runnable class to add a runnable class to your project.
  2. Copy and paste the following code into the class to test your data entity.
    public static void main(Args _args)
    {
        FMLabCustomerEntity customer;
        str license = "License";
        Random r = new Random();
        int rand = r.nextInt();
        license = license + int2str(rand);
    
        //Create a new record in FM lab customer entity
        customer.clear();
        customer.FirstName = "Bob";
        customer.LastName = "Smith";
        customer.DriverLicense = license;
        customer.insert();
    
        info(strfmt("Tried to insert customer '%1 %2' with license %3", 
            customer.FirstName, customer.LastName, customer.DriverLicense));
    
        //Display newly created record
        select forupdate customer where customer.DriverLicense==license;
        info(strfmt("Found newly created customer '%1 %2' with license %3", 
            customer.FirstName, customer.LastName, customer.DriverLicense));
    
        //Now delete the record from the entity
        customer.delete();
        select customer where customer.DriverLicense==license ;
        info(strfmt("Deleted customer does not exist: license- %1", customer.DriverLicense));
    }
    
  3. Run the code in debugger to set it as a startup object.
  4. To validate the entity, view the Infolog in the debugger window or in notifications on the website. You will see that three successful messages are logged. You will also see the actions that were taken.

Importing data by using entities

Data entities that have the Data Management Enabled property can be used to import and export data in various file formats. In this section, you will import data in a CSV file format for the FMLabCustomer entity.

File import

After you create your data entity, you can validate import/export.
  1. Create a sample CSV file that you can import. Copy the following text, and save it as FM Lab Customer Import.csv.
    CELLPHONE,DRIVERSLICENSE,EMAIL,FIRSTNAME,LASTNAME,CUSTOMERGROUP,ADDRESSLINE1,ADDRESSLINE2,CITY,STATE,ZIPCODE,COUNTRY(999) 555-0100,S615-3939-2349,chris.spencer@adatum.com,Chris,Spencer,adv\_mem\_1,444 Main Street,,Orlando,FL,77899,US(188) 555-0101,S615-3939-2350,Ichiro.lannin@blueyonderairlines.com,Ichiro,Lannin,non\_mem\_1,12 Long Street,,New York City,NY,99087,US(777) 555-0102,S615-3939-2351,josh.smith@fourthcoffee.com,Josh,Smith,adv\_mem\_1,9606 122th Avenue,,Sydney,TX,99874,US(456) 555-0103,S615-3939-2352,Vince@fabrikam.us,Vince,Ahmed,non\_mem\_1,123 Microsoft Way,Unit 87,Seattle,WA,90001,US(345) 555-0104,S615-3939-2353,tony.parker@lucernepublishing.com,Tony,Parker,non\_mem\_1,12012 11th PLNE,Apt 160,San Francisco,CA,75645,US(312) 555-0105,S615-3939-2354,Julia@fineartschool.net,Julia,Natarajan,exec\_mem\_1,449 Long Street,Apt 160,Bruxelles,ID,34213,US
    
  2. Click User Dashboard > Data management.
  3. In the Data Management workspace, click the Import tile.
  4. On the Import page, enter the import details, as shown in the following screen shot.
    Import new record
  5. Click the Upload data button next to the Upload file for entity field, and select the CSV file that you created.
  6. After the file is uploaded, you will notice that the entity is added to the middle section. You will also receive an error that states that the mapping isn't valid. A few fields aren't mapped correctly between the source file and the target entity.
  7. In the entities list, click View map.
  8. AddressLine1 and AddressLine2 are two fields in the source that aren't mapped to target fields. In the visual mapper, or details view, map these fields as follows, and then click Save:
    • AddressLine1 – Address1
    • AddressLine2 – Address2
    Map source to staging
  9. Click the Back button in your browser to go back to the Import job page. The check mark in the entities list indicates that the entity is now ready for import.
    Import new record 2
  10. Click Import Now. After the import is completed, the job status page opens.

Consuming entities by using OData

In this section, you will learn how to expose and consume an entity for OData. Before you begin, verify that the Fleet demo data is loaded from the client: [baseURL]/?f=FMSetup

Review the FleetRental entity and add a navigation property for OData

You will review the existing FleetRental entity and then create a relationship from one data entity to another. This relationship will be used as a navigation property for OData entities.
  1. In Solution Explorer, verify that you're in the FMEntityLab project.
  2. In Application Explorer, search for FMRentalEntity, right-click it, and then select Add to Project.
  3. In Application Explorer, search for FMCustomerEntity, right-click it, and then select Add to project.
  4. In Solution Explorer, right-click FMRentalEntity, and then select Open.
  5. In the view designer, select the root node, FMRentalEntity, and review the following properties.
    PropertyValueDescription
    IsPublicYesWhen this property is set to Yes, the entity is visible by using the OData application programming interface (API).
    Public Entity NameFleetRentalThe name that will be used in the OData APIs for EntityType.
    Public Collection NameFleetRentalsThe name that will be used for the OData collection entity.
  6. In the view designer, expand the Relations node.
  7. Select Customer Relation, and then click Delete.
  8. Right-click Relations, and then select New > Relation.
  9. Select Relation1, and set the following properties.
    PropertyValue
    CardinalityZeroMore
    NameCustomerRelation
    Related Data EntityFMCustomerEntity
    Related Data Entity CardinalityExactlyOne
    Related Data Entity RoleCustomerRole
    Relationship TypeAssociation
    RoleRental
  10. In the view designer, right-click the CustomerRelation node, and then select New > Normal.
  11. Right-click the new node under CustomerRelation, and then select Properties.
  12. Set the following properties.
    PropertyValue
    FieldCustomerDriverLicenseThis is the foreign key field on FMRentalEntity.
    Related FieldDriverLicenseThis is the unique key on FMCustomerEntity.
    The following screen shot shows the relation in Visual Studio.
    FMRentalEntity - Solution explorer
  13. On the BUILD menu, click Build Solution to save your changes and build the project. You can view the build progress in the Output window.
  14. To update the OData endpoint with the changes, you must run an iisreset command. Open a Command Prompt window as an administrator, and enter iisreset.
You've now created a navigation property between FMRentalEntity and FMCustomerEntity.

Use standard OData syntax to retrieve data

In this section, you will use some of the standard OData syntax to navigate and query the OData entities that are exposed in the Fleet Management model. First, follow these steps to enable Internet Explorer to view JSON formatted data.
  1. Close all Internet Explorer windows.
  2. Go to C:\FMLab, and select and double-click the json.ie.reg file.
  3. In the Registry Editor dialog box, click Yes.
  4. Click OK.
You can now use Internet Explorer to explore some OData URIs.
  1. Start Internet Explorere, and enter the following URL in the address bar: [baseURL]/data/$metadata You will see all the metadata that is associated with OData entities.
     Note
    The metadata might take a few minutes to appear the first time that you access it. In the XML, you can see all of the properties and navigation properties associated with the OData entities.
  2. In the browser, find FleetRental. The following screen shot shows the metadata of the FleetRental entity, together with the new relationship, NavigationProperty.
    FleetRental metadata
  3. To view all the customers in the Fleet Management application in JSON format, enter the following URL into the address bar of your browser: [baseURL]/data/FleetCustomer
     Note
    Entity names are case-sensitive.
  4. If you don't want to retrieve all properties for the customers, you can retrieve just selected properties. For example, to retrieve only FirstName and LastName, enter the following URL: [baseURL]/data/FleetCustomers?$filter=FirstName.LastName
  5. You can also apply filters. For example, to filter on all customers where FirstName=Phil, enter the following URL: [baseUrl]/data/FleetCustomers?$filter=FirstName%20eq%20'Phil'
     Note
    These URLs won't work if you copy and paste them. You must manually enter them in the address bar.
  6. To retrieve all the Rental records, together with all details of the customers, enter the following URL: [baseURL]/data/FleetRentals?$expand=CustomerRole The following example shows a Rental record, together with details of the linked customer, in JSON format.
    "@odata.context":"https://testax32aos.cloud.test.dynamics.com/en/data/$metadata#FleetRentals","value":
    {  
        { 
            "@odata.etag":"W/"JzEsNTYzNzE0NDU3NjsxLDU2MzcxNDQ1NzY7MTc4NjA2OTg1Niw1NjM3MTQ0NjA1Jw=="",
            "Comments":"","StartMileage":0,"VehicleRatePerDay":40,"CustomerDriverLicense":
            "S468-3184-6541","VehicleRateTotal":280,"VehicleId":"Litware_LitwareFour_1",
            "RentalId":"000001",
            "StartFuelLevel":"Full","StartDate":"2010-04-09T00:00:00Z","CustomerLastName":"Spencer",
            "EndMileage":0,"VehicleVIN":"2J4FY19P0NJ710529",
            "RecId":5637144576,"EndDate":"2010-04-16T00:00:00Z",
            "VehicleRatePerWeek":270,"CustomerFirstName":"Phil","State":3,
            "EndFuelLevel":"","CustomerRole":
    
            {"@odata.etag":"W/"JzEsNTYzNzE0NDU3NjsxLDU2MzcxNDQ1NzYn"",
            "CellPhone":"(999) 555-0100",
            "DriverLicense":"S468-3184-6541","AddressLine2":"",
            "State":"FL","Country":"US","FirstName":"Phil",
            "Email":"phil.spencer@adatum.com","CustomerGroup":
            "adv_mem_1","AddressLine1":"167 BBN Way","City":"Orlando",
            "ZipCode":77899,"RecId":5637144576,"LastName":"Spencer"
        }  
    }
    

Add an action to OData entity

Actions provide a way to inject behaviors into the data model. In Dynamics 'AX 7,' you add actions by adding a method to the data entity and then decorating the method with specific attributes. In this section, we'll walk through the steps for adding an action.
  1. In Solution Explorer, right-click FMRentalEntity, and then select View code.
  2. Copy the following code lines, and paste them into the Code window.
    public class FMRentalEntity extends common
    {
        [SysODataActionAttribute("ReturnRental", true)]
        public str ReturnRental()
        {
            //do something
            return "Rental was successfully returned. Thanks for your business";
        }
    }
    
  3. On the BUILD menu, click Rebuild Solution to save your changes and build the project. You can view the build progress in the Output window.
  4. To update the OData endpoint with the changes, you must run an iisreset command. Open a Command Prompt window as an administrator, and enter iisreset.
    The action that you just added can be invoked through code, as you will see in the next section.

Consume the OData API from an external console application

In this section, you will use a console application to consume the OData endpoints that are exposed in the Fleet Management application. The console application first creates a new customer and then creates a new reservation for that customer. This tutorial shows how easy it is to use OData together with standard .NET Windows Communication Foundation (WCF) data service libraries to integrate with Dynamics AX.
  1. Start a new instance of Visual Studio.
  2. On the File menu, click Open > Project/Solution.
  3. In the Open Project dialog box, browse to C:\FMLab\Odata4ConsoleApplication, and then select Odata4ConsoleApplication.csproj.
  4. Click Open. The Odata4ConsoleApplication project appears in Solution Explorer.
  5. In Solution Explorer, double-click OdataProxyGenerator.tt.
  6. In the code editor, replace the following string with your organization's URL.
    <baseURL> public const string MetadataDocumentUri = "<baseURL>/data/"
    
  7. Save the OdataProxyGenerator.tt file.
  8. In the Save of Read-only file dialog box, click Overwrite. The proxy class for the OData metadata endpoint is generated. This operation might take a few minutes.
  9. In Solution Explorer, double-click Program.cs.
  10. Replace the value of the dynamicsBaseUri variable with your organization's URL.
  11. Verify that there is a final closing slash (/) in the URL, and then click Save.
  12. In the Save of Read-only file dialog box, click Overwrite.
  13. Press F5 to run the application, and then follow the instructions in the output console window. The application might prompt you for your Dynamics AX credentials. After the application has run, the new customer and the corresponding reservation are created.
  14. Follow these steps to verify that the new reservation appears on the Rental page:
    1. Start Internet Explorer, and enter the following URL in the address bar: [baseURL]/?mi=FMRental The FMRental page shows the list of rentals.
      Rental list
    2. At the bottom of the list, click Next to view the next page. On this page, you can see that the reservation was created for the new customer that you added.
      customer reservation
This completes the walkthrough, where you've seen an external client interacting with the Fleet Management model by using OData endpoint.
Above post is taken from https://docs.microsoft.com/

Blog Post 6: Bonus – Building Your First Custom Copilot Plugin in X++

Blog Post 6: Bonus – Building Your First Custom Copilot Plugin in X++  Introduction In our previous posts, we explored what Copilot can do o...