Tag Archives: D3FOE
Set form control access via security role in D365 Finance
In some of the cases instead of providing security to whole form we need it for particular form control.So this blog will help you with providing access to form control via security roles.If you want to know more about security roles you can use my previous blog . First of all we need form control where we need to set some of the properties as follows. In our case we are using laid off button as shownNow select the button and press F4 for its properties and set needed permision to manual as follows Now in your desired security privilege you can either directly set form control permissions or Entry Points.For form control permission method right click on form control permission and select new form and after that set name property to your desired form (Hcmworker in our case) as follows Now right click on your form and select New control option as follows and set control name and permission for it as follows For Entry point method you need first need to add new entry point and set its object type and object name properties or for existing ones select desired entry point and click on drop down arrow and on controls right click and select new control.And now set its grant and name properties to desired control and its access rights After this you need to assign this privilege in desired security role and security duty as previously discussed in security role blog
Deploy Dynamics 365 Operations Environment using Lifecycle Services Part – 1
In this blog article, we will see how we can create a project and deploy a dynamic 365 operations environment using Lifecycle services. Prerequisites: Azure Subscription Lifecycle Service Account Step by Step approach: Environment Setup Azure Subscription: Login to the Azure portal using credential use below URL and buy Pay-As-You-Go subscription as LCS will consume more resource and if we choose start free option it will give error later when we deploy the VM. “https://portal.azure.com/” Once we done with the subscription go to the subscription tab and select the Access Control option and create a role select the role as the Contributor and Add a user select the user as the “Dynamic Deployment Services.” We can now login to the Lifecycle Services remember we should login in LCS using the account which has the admin access to the subscription. After login we can see the following screen. The first step in LCS is to create new project so click on (+) sign to create new project. Once we click on (+) sign we’ll have different option the option may vary as per the version of LCS you are using, here we are setting up environment for development and learning purpose select the “Migrate, Create Solutions, and Learn” option. Enter the project details and click on the create option. All the information is related to the how you want your project settings to show and the methodology option let you select what you want to shows up on the default project information that shows up in lifecycle services so the migrate and create dynamic 365 for operation solution give you these options. Once we click on create we’ll land to the life cycle project homepage Access the Azure subscription:- Scroll to the right and click on the project settings We are accessing the azure subscription so click on the Azure connectors options we’ll see the following screen. The first step is to authorize your organisation in the LCS click on the authorize link. Linking LCS to Azure subscription click on the Add option and set the required option make sure the subscription id is same as you have in the azure portal as we may have multiple subscription set so keep in mind to use correct subscription. Once we fill the required details click on the next. Once we click on next we’ll required to authorize the user to the subscription or we can download the certificate and upload to the azure portal by going to the Subscription > Management Certificates > Upload then upload the certificate that we have downloaded. Select the server environment region for LCS. Now we can see the azure connection in the project setting we got Azure subscription id that is showing . Deployment for the virtual machine In newly created environment go to the Project and in environment tab click on the (+) sign Once we click on (+) sign we’ll application platform option choose the latest application and platform version. Select the environment topology here we are selecting Demo environment Specify the Deploy environment setting by clicking on the Advance setting option Choose the below option and leave the other settings as default Click on the next. We can set size of the virtual machine of our choice it’s fine to keep the default settings and go ahead. Once confirm and deploy the VM deployment will start, usually deployment will take 3 hr. So, this will create the D365 Operation Environment for us. In next blog we’ll see how to setup the post deployment configuration setting for the environment
Create Item Requirement from Item Forecast using X++ in D365 Operations
Introduction: In this blog article, we will see how we can create Item Requirement on insertion of Item Forecast using code. Steps: Create Extension Class for ForecastSales Table that is Item Forecast and using CoC for post insert() method we will initialize Item Requirement. We will call a new class which is created in Step 2. public void insert() { next insert(); SalesType salesType = SalesType::ItemReq; CFSCreateItemReqFrmItemForecast createItemReq = new CFSCreateItemReqFrmItemForecast(); createItemReq.initParameters(this); createItemReq.copyToSalesLine(SalesType); } Create a new class that will initialize values and insert record in Item Requirement form. class CFSCreateItemReqFrmItemForecast { ForecastSales forecastSales; } In the new class create a method initParameter. This method will initialize ForecastSales object. void initParameters(ForecastSales _forecastSales) { forecastSales = _forecastSales; } Create another method ‘copytoSalesLine’. It will validate the record and call other methods to copy values to SalesLine Table. public void copyToSalesLine(SalesType _salesType) { ProjTable projTable = ProjTable::find(forecastSales.ProjId); if (_salesType == SalesType::ItemReq) { if (!ProjStatusType::construct(projTable).validateWriteItemRequirement()) { throw error(“@SYS18447”); } } else { if (!ProjStatusType::construct(projTable).validateWriteSalesLine()) { throw error(“@SYS18447”); } } SalesLine salesLine = this.initializeSalesLine(_salesType, forecastSales, projTable); salesLine.createLine(false, // Validation false, // Init from SalesTable true, // Init from InventTable true, // Calc invent Qty false, // Search markup – copied from salesQuotationline false, // Search price – copied from salesQuotationline false, // Check reservation true); // Skip creditlimit check this.updateSalesLine(salesLine, forecastSales); salesLine.update(); } Create a new method ‘initializeSalesLine’. It is called from copyToSalesLine(). protected SalesLine initializeSalesLine(SalesType _salesType, ForecastSales _forecastSales, ProjTable _projTable) { SalesLine salesLine; salesLine.SalesType = _salesType; salesLine.initValue(); salesLine.setInventDimId(_forecastSales.InventDimId); salesLine.ItemId = _forecastSales.ItemId; salesLine.SalesQty = _forecastSales.SalesQty; salesLine.SalesUnit = _forecastSales.SalesUnitId; salesLine.ProjId = _forecastSales.ProjId; salesLine.ActivityNumber = _forecastSales.ActivityNumber; salesLine.CurrencyCode = _forecastSales.Currency; salesLine.initFromProjTable(_projTable, false); return salesLine; } Create a new method updateSalesLine(). It is called from copyToSalesLine() method. protected void updateSalesLine(SalesLine _salesLine, ForecastSales _forecastSales) { _salesLine.DefaultDimension = _salesLine.copyDimension(_forecastSales.DefaultDimension); _salesLine.ProjLinePropertyId = _forecastSales.ProjLinePropertyId; _salesLine.TaxGroup = _forecastSales.TaxGroupId; _salesLine.TaxItemGroup = _forecastSales.TaxItemGroupId; _salesLine.ProjCategoryId = _forecastSales.ProjCategoryId; _salesLine.CostPrice = _forecastSales.CostPrice; _salesLine.SalesPrice = _forecastSales.SalesPrice; _salesLine.LinePercent = _forecastSales.DiscPercent; _salesLine.LineDisc = _forecastSales.DiscAmount; _salesLine.LineAmount = 0; _salesLine.LineAmount = _salesLine.calcLineAmount(); SalesLineType_ItemReq::setSalesLineReceiptDate(_salesLine); }
Post Ledger Journal using X++ in D365 Operations
Introduction: In this blog article, we will see how we can post the journal by using code. How to do? Create a new method and write below code. In this code you declare object of Class ‘LedgerJournalCheckPost’. This class will use journal buffer and post it. public void postJournal(LedgerJournalTable ledgerJournalTable) { LedgerJournalCheckPost jourPost; jourPost = LedgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable, NoYes::Yes); jourPost.runOperation(); }
Create Fixed Asset Journal using X++
In this blog article, we will see how we can create Fixed Asset Journal using X++. Write below code to create Journal Header in LedgerJournalTable Table and Lines record in LedgerJournalTrans and LedgerJournalTrans_Asset Tables. public void createFixedAssetJournal() { LedgerJournalTable ledgerJournalTable; LedgerJournalTrans ledgerJournalTrans; LedgerJournalTrans_Asset ledgerJournalTrans_Asset; Assettable assetTable; ledgerJournalTable.initValue(); ledgerJournalTable.JournalNum = JournalTableData::newTable(ledgerJournalTable).nextJournalId(); ledgerJournalTable.Posted = NoYes::No; ledgerJournalTable.JournalName = ‘ACQUI’; ledgerJournalTable.JournalType = LedgerJournalType::Assets; ledgerJournalTable.initFromLedgerJournalName(ledgerJournalTable.JournalName); ledgerJournalTable.insert(); ledgerjournalTrans.initValue(); ledgerJournalTrans.CurrencyCode = Ledger::accountingCurrency(CompanyInfo::find().RecId); ledgerJournalTrans.AccountType = LedgerJournalACType::FixedAssets; ledgerJournalTrans.TransactionType = LedgerTransType::FixedAssets; ledgerJournalTrans.Approved = NoYes::Yes; ledgerJournalTrans.Approver = HcmWorker::userId2Worker(curuserid()); ledgerJournalTrans.LineNum = LedgerJournalTrans::lastLineNum(ledgerJournalTrans.JournalNum) + 1; ledgerJournalTrans.TransDate = DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()); ledgerJournalTrans.LedgerDimension = LedgerDynamicAccountHelper::getDynamicAccountFromAccountNumber(AssetTable.AssetId,LedgerJournalACType::FixedAssets); ledgerJournalTrans.accountName(); ledgerJournalTrans.AmountCurDebit = ’45’; ledgerJournalTrans.OffsetAccountType = LedgerJournalACType::Ledger; ledgerJournalTrans.OffsetLedgerDimension = ledgerJournalTrans.getOffsetLedgerDimensionForLedgerType(AssetLedgerAccounts::assetOffsetLedgerDimension(AssetTable.AssetId, AssetTable.assetBookCurrent().BookId, AssetTransType::Acquisition),curExt()); ledgerJournalTrans.insert(); ledgerJournalTrans_Asset.initValue(); ledgerJournalTrans_Asset.RefRecId = ledgerJournalTrans.RecId; ledgerJournalTrans_Asset.AssetId = assetTable.assetId; ledgerJournalTrans_Asset.TransType = AssetTransTypeJournal::Acquisition; ledgerJournalTrans_Asset.BookId = AssetTable.assetBookCurrent().BookId; ledgerJournalTrans_asset.insert(); ttsbegin; LedgerJournalTable.selectForUpdate(true); LedgerJournalTable.numOfLines = LedgerJournalTable.numOfLines(); LedgerJournalTable.update(); ttscommit; }
Create Fixed Asset using X++
In this blog article, we will see how we can create a Fixed Asset using code based on AssetGroupID. Add below code in class to create a Fixed Asset, public void createFixedAsset(AssetGroupId assetGroupId) { AssetTable assetTable; NumberSeq numberSeq; assetTable.initValue(); assetTable.assetGroup = AssetGroupId; //Initialize Number Seq for Asset Id numberSeq = assetTable.initAssetNumberSeq(assetTable.Assetgroup); AssetTable.AssetId = NumberSeq.num(); //Initialize other fields based on Asset Group assetTable.initFromAssetGroupId(assetTable.Assetgroup); //Initialize name and Name Alias fron Item Id assetTable.Name = InventTable::find(‘ITM1104’).itemName(); assetTable.NameAlias = assetTable.Name; //Validate and Insert Fixed Asset. On insertion asset book is also created assetTable.validateWrite(); assetTable.insert(); }
Fetch FormControl and value of different type in Event Handler of D365 Operations
Introduction: In this blog article, we will see how we can fetch Form Control and its value which is of different datatype in EventHandler in D365 Operations Scenario: I am working on Global Address Book functionality for checking Duplicate values for PartyID (String), Tax Id (CheckBox) and Tax Id Type (ComboBox). I am using Event Handler of form method to enable a button based on value of above three fields. Steps: Create Event Handler with below code: [PostHandlerFor(formStr(DirPartyCheckDuplicate), formMethodStr(DirPartyCheckDuplicate, enableSearch))] public static void DirPartyCheckDuplicate_Post_enableSearch(XppPrePostArgs args) { FormRun formRun = args.getThis() as FormRun; FormCheckBoxControl TaxId = formRun.design(0).controlName(“TaxId”) as FormCheckBoxControl; FormStringControl PartyNumber = formRun.design(0).controlName(“DirPartyTable_PartyNumber”) as FormStringControl; FormComboBoxControl TaxIdType = formRun.design(0).controlName(“TaxIdType”) as FormComboBoxControl; FormControl searchBtn = formRun.design(0).controlName(“searchBtn”); if(TaxId.value() || PartyNumber.valueStr() || TaxIdType.valueStr()) { searchBtn.enabled(true); } else { searchBtn.enabled(false); } }
Reading more then 10K records in D3FOE OData API
Introduction: We all know Dynamics 365 Finance and Operations has limitation of 10K records to be fetched at a time using Data Entity. While reading records from D3FOE for CRUD operations in OData API you will face issue if you want to process more than 10K records at a time. You can resolve this issue by using query parameter ‘skip’ and ‘top’. Use the below syntax to query records while reading from D3FOE: DataServiceQuery<[EntityName]> EntityObject = context.[EntityName].AddQueryOption(“$skip”, 10000).AddQueryOption(“$top”, 10000); where, EntityName = Name of data entity from where you want to read records Skip = it will skip the number of records you specified from the fetched records Top = It will select the number of records specified after skipping the records Example: If there are 30K records in CustCustomers then above line will skip 10K records and then pick the next top 10K records. So records selected will be from 10001 to 20000. DataServiceQuery<CustCustomers> EntityObject= context.[CustCustomers].AddQueryOption(“$skip”, 10000).AddQueryOption(“$top”, 10000); You can also get the total count of records and then run a loop until max count of records and increment the skip with 10K on each loop and top with 10K. Using this you can read ‘n’ number of records.
Commands to Import .bacpac file to D3FOE SQL Server
Introduction: This blog article will explain how to import a .bacpac file to Microsoft SQL Server which is created from Finance and Operations database that is based on Azure SQL Server. You can refer steps here for creating .bacpac file. Following points are recommended for smooth and secure importing of .bacpac file Take a backup of existing database so you can revert if required. Import the database with a new name and modify it later once the entire process is completed error free. Copy the .bacpac file to local computer where you want to import the database for better performance. Steps: Run command prompt as an administrator. Run the below command to Import the database. cd C:\Program Files (x86)\Microsoft SQL Server\130\DAC\bin SqlPackage.exe /a:import /sf:D:\Exportedbacpac\SSProd.bacpac /tsn:localhost /tdn:SSProd /p:CommandTimeout=1200 where, tsn (target server name) – The name of the SQL Server to import into. tdn (target database name) – The name of the database to import into. The database should not already exist. sf (source file) – The path and name of the file to import from. Update the database: Run the following script against your database to add the users you deleted while creating .bacpac file. Update your database name in Alter Command. CREATE USER axdeployuser FROM LOGIN axdeployuser EXEC sp_addrolemember ‘db_owner’, ‘axdeployuser’ CREATE USER axdbadmin FROM LOGIN axdbadmin EXEC sp_addrolemember ‘db_owner’, ‘axdbadmin’ CREATE USER axmrruntimeuser FROM LOGIN axmrruntimeuser EXEC sp_addrolemember ‘db_datareader’, ‘axmrruntimeuser’ EXEC sp_addrolemember ‘db_datawriter’, ‘axmrruntimeuser’ CREATE USER axretaildatasyncuser FROM LOGIN axretaildatasyncuser EXEC sp_addrolemember ‘DataSyncUsersRole’, ‘axretaildatasyncuser’ CREATE USER axretailruntimeuser FROM LOGIN axretailruntimeuser EXEC sp_addrolemember ‘UsersRole’, ‘axretailruntimeuser’ EXEC sp_addrolemember ‘ReportUsersRole’, ‘axretailruntimeuser’ CREATE USER axdeployextuser WITH PASSWORD = ‘<password from LCS>’ EXEC sp_addrolemember ‘DeployExtensibilityRole’, ‘axdeployextuser’ CREATE USER [NT AUTHORITY\NETWORK SERVICE] FROM LOGIN [NT AUTHORITY\NETWORK SERVICE] EXEC sp_addrolemember ‘db_owner’, ‘NT AUTHORITY\NETWORK SERVICE’ UPDATE T1 SET T1.storageproviderid = 0 , T1.accessinformation = ” , T1.modifiedby = ‘Admin’ , T1.modifieddatetime = getdate() FROM docuvalue T1 WHERE T1.storageproviderid = 1 –Azure storage ALTER DATABASE [<your AX database name>] SET CHANGE_TRACKING = ON (CHANGE_RETENTION = 6 DAYS, AUTO_CLEANUP = ON) GO — Begin Refresh Retail FullText Catalogs DECLARE @RFTXNAME NVARCHAR(MAX); DECLARE @RFTXSQL NVARCHAR(MAX); DECLARE retail_ftx CURSOR FOR SELECT OBJECT_SCHEMA_NAME(object_id) + ‘.’ + OBJECT_NAME(object_id) fullname FROM SYS.FULLTEXT_INDEXES WHERE FULLTEXT_CATALOG_ID = (SELECT TOP 1 FULLTEXT_CATALOG_ID FROM SYS.FULLTEXT_CATALOGS WHERE NAME = ‘COMMERCEFULLTEXTCATALOG’); OPEN retail_ftx; FETCH NEXT FROM retail_ftx INTO @RFTXNAME; BEGIN TRY WHILE @@FETCH_STATUS = 0 BEGIN PRINT ‘Refreshing Full Text Index ‘ + @RFTXNAME; EXEC SP_FULLTEXT_TABLE @RFTXNAME, ‘activate’; SET @RFTXSQL = ‘ALTER FULLTEXT INDEX ON ‘ + @RFTXNAME + ‘ START FULL POPULATION’; EXEC SP_EXECUTESQL @RFTXSQL; FETCH NEXT FROM retail_ftx INTO @RFTXNAME; END END TRY BEGIN CATCH PRINT error_message() END CATCH CLOSE retail_ftx; DEALLOCATE retail_ftx; — End Refresh Retail FullText Catalogs Run the re-provision tool: To ensure Retail components are functional run the re-provision tool. Find steps here on how to run the tool. Start using the new database: Stop the below service to switch the database. World wide web publishing service. Finance and Operations Batch Management Service. Management Reporter 2012 Process Service. Once the services are stopped, rename your original database to ‘AxDB_orig’ and the new database to ‘AxDB’. Restart the service. Conclusion: This is how you can create a new database and import the data from a .bacpac file. If you face any issue then you can switch to original database or restore the copy of original database created prior to import.
Change Tracking for Data Entities in D365 Operations
Introduction: In this blog article, we will see how we can track changes in data made since last export using Data Entities in D365 Operations. It is basically an SQL Change Tracking feature. Steps: Go to Data Management -> Data Entities. Select the Entity for which you want to enable Change Tracking. In the Action Pane, go to Change Tracking. There are 3 options: Enable primary table – It will only track changes made on root table. Enable entire entity – It will enable tracking for all Writable Datasource used in the entities. Enable custom Query – You can create a custom query to track changes on the required tables. You can also disable the change Tracking by clicking on ‘Disable Change Tracking’ option. You should be careful while enabling change tracking as it will require additional processing for maintaining data for changed records.