ExtensionOf(classStr(InventQuarantineOrder_Scrap))]
public final class InventQuarantineOrder_Scrap_Extension
{
private RecordStatus status;
#define.CurrentVersion(1)
#localmacro.CurrentList
status
#endmacro
[DataMemberAttribute]
public RecordStatus parmRecordStatus(RecordStatus _status)
{
status = _status;
return status;
}
public container pack()
{
container packedClass = next pack();
return SysPackExtensions::appendExtension(packedClass, classStr(InventQuarantineOrder_Scrap_Extension), this.packMyExtension());
}
public boolean unpack(container _packedClass)
{
boolean result = next unpack(_packedClass);
if (result)
{
container packedClassExtension = SysPackExtensions::findExtension(_packedClass, classStr(InventQuarantineOrder_Scrap_Extension));
//Also unpack the extension
if (!this.unpackMyExtension(packedClassExtension))
{
result = false;
}
}
return result;
}
private container packMyExtension()
{
return [#CurrentVersion, #CurrentList];
}
private boolean unpackMyExtension(container _packedClass)
{
Integer version;
if (typeOf(conPeek(_packedClass, 1)) == Types::Integer)
{
version = conPeek(_packedClass, 1);
}
else
{
version = RunBase::getVersion(_packedClass);
}
switch (version)
{
case #CurrentVersion:
[version, #currentList] = _packedClass;
break;
default:
return false;
}
return true;
}
}
Note: This logic is only related to get the values fromLocal Macro which we needed in the custom dialog field along with STd dialog fields.How to get packed list(Pack & Unpack) values of custom fields using extensions in RunBase class in D365
Keywords to use while working on code upgrading project from AX 2012 to D365
Un-mark settlement and reverse the customer payment journal transaction
public static void unsettlementAndReverse(Voucher _voucher)
{
CustTable custTable;
CustTrans findCustTrans;
CustSettlement custSettlement;
SpecTransManager specTransManager;
AmountCur balanceAmount;
select firstonly * from findCustTrans
where findCustTrans.Voucher == _voucher;
if (findCustTrans.RecId)
{
balanceAmount = findCustTrans.remainAmountCur();
if (balanceAmount == 0)
{
custTable = custTable::find(findCustTrans.AccountNum);
select firstonly custSettlement
where custSettlement.TransCompany == findCustTrans.dataAreaId && custSettlement.TransRecId == findCustTrans.RecId && custSettlement.AccountNum == findCustTrans.AccountNum;
specTransManager = SpecTransManager::newRefTableId(custTable, tablenum(custSettlement), true);
specTransManager.insert(custSettlement.DataAreaId, custSettlement.TableId, custSettlement.RecId, custSettlement.SettleAmountCur, findCustTrans.CurrencyCode);
// custSettlement.CustVendSettlement::markOffsets(specTransManager, findCustTrans.CurrencyCode, true);
// custSettlement.CustVendSettlement::unmarkThisAndRelatedOffsets(specTransManager);
custSettlement.CustVendSettlement::markThisAndRelatedOffsets(specTransManager,findCustTrans.CurrencyCode);
if (CustTrans::reverseTransact(custTable, null, settleDatePrinc::DateOfPayment, custSettlement.TransDate))
{
specTransManager.deleteAll();
}
}
}
}
H@ppy D@xing!!!Testing custom service/odata logic in postman for D365 F&O
Hi All,
Today I'm sharing few thoughts while I was testing the custom service logic from Postman.
I have searched many sources and blogs regarding this concept, But all shared about the logic of building the custom service in Dynamics365 and no one shared how to test the logic which was written in those x++ classes or to test the request/response output.
Below are the steps need to follow for REST API custom service through POSTMAN.
1. Register an app (like for dev envn or QA/UAT) for postman testing.
2. Client id will be auto populate and mention the below options to register app.
- Select accounts in any organizational directory (Any Azure AD directory - Multitenant)
- Give Redirect Url as http://localhost
3. Go to API permission tab Create API Permission and Mention the type of app (like Custom service or AX or Odata).
4. Go to Manifest and edit few lines for
"allowPublicClient": true, "oauth2AllowImplicitFlow": true
5. Go to Certificate and secrets tab and Create a Secret token and save the value in the notepad, Why because its one time visible.
6. Go to Certificate and secrets tab and Create a Secret token and save the value in the notepad, Why because its one time visible.
7. Go to Dynamics 365 F&O >>Login>>System Administration>>Setup>>Azure Active Directory Application form>>Click New Button and enter Client Id and User
8. Now go to postman website and download the desktop app. Create the environment(in my case its Dev2) and create a collection(GetAccessToken) and mention the below values in the body level.
Client id : you will get it in portal.azure.com>>app registration.
Client_secret: secret value which we saved in notepad
Grant_type : Client_Credentials
Scope: https://xxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudax.dynamics.com/.default ((dot)default mention this at the end) replace xxxxxxx with your environment url.
9. Mention this in url column (https://login.microsoftonline.com/xxxxxxxxxxxxxxxxxxxxxxx/oauth2/v2.0/token)
( https://login.microsoftonline.com/TenentId/oauth2/v2.0/token ) and post it.
10. Go to test tab and run the below code (Please expose all the client id,BearerToken,Sercet token and grantType as Global Variables)
<pre><code class="language-C#">
var json = JSON.parse(responseBody);
tests["Get Azure AD Token"] = !json.error && responseBody !== '' && responseBody !== '{}' && json.access_token !== '';
postman.setEnvironmentVariable("bearerToken", json.access_token);
</code></pre>
11. Create one more collection for your requirement(Like Calling Custom service) Eg: In my case its Call Service.
12. Below is the code of sample as JSON file.
(Note: All the below parameters are parameter methods[parm methods] which I created in RequestDataContract Class.)
<pre><code class="language-C#">
{ "_request" :
{
"PaymentReference": "100000",
"TransDate": "2021-09-28",
"BankTransactionType": "ACH-P",
"PaymOriginId": "ACI-PP",
"PaymMethodName": "EPAY",
"InvoiceId": " ",
"AmountCurCredit": "0.00",
"AmountCurDebit": "25.47",
"AmountCur": "0.00",
"CustAccount": "100000451",
"DivisionId": "Test",
"Description": "ACH-P",
"TransactionText" :"TEST",
"ChequeStatus": "Created",
"OriginalConfirmation": "100",
"LedgerJournalId": " "
}
}
</code></pre>
13.Select POST type and paste custom service url which we created and Click Send Button
For Custom Service:
For Odata:
https://xxxxxxxxxxxxxxxx.cloudax.dynamics.com/data/[DataentityName]
Output:
This output will get depends upon the respond data contract parameters which we created in Dynamics 365 F&O
Thanks....
Difference between Power Automate/Flow Vs Azure Logic Apps
1) Most of the connectors are available in both.
2) Both are cloud based services for automating workflows across apps.
Thanks...
Error: One or more checked work items failed transition error while TFS check-In (VS,Dynamics365)
Hi There,
Some times when we complete our development/Bug and try to do check_In we will face following error.
Issue:
"One or more checked work items failed transition testing due to invalid field values.Please correct the values and try the check-in."
Solution: Change the option to Associate from Resolve as below screenshot.
Output:
Difference between Hookable vs Wrappable vs Replaceable in D365
Hi All,
Please find the below the concept of all Hookable vs Wrappable vs Replaceable explained in detail.
Hookable
If a method is hookable, extenders can subscribe to pre-events and post-events.
For public methods, you can opt out by adding [Hookable(false)] to the method.
You can opt in for private and protected methods by adding [Hookable(true)] to the method.
If a method is explicitly marked as [Hookable(false)], then it is not wrappable.
Best practices when you write code
When a method is hookable, the compiler generates extra intermediate language (IL) code to enable the method as an extension point. Although the extra code has performance overhead, this overhead is negligible in most cases. However, for performance-critical methods, consider marking the method as non-hookable.
Wrappable
If a method is wrappable, extenders can wrap it by using Chain of Command (CoC). Extenders must call next, because they aren't allowed to break the CoC.
For protected and public methods, you can opt out by adding [Wrappable(false)] to the method.
You can't opt in for private methods.
Best practices when you write code
CoC resembles inheritance in many ways. Typically, if you want other people to be able to call your method but not change it, you mark the method as final. Consider marking these methods as non-wrappable or non-hookable.
Replaceable
If a method is replaceable, extenders can wrap it by using CoC, but they don't have to unconditionally call next. Although extenders can break the CoC, the expectation is that they will only conditionally break it. The compiler doesn't enforce calls to next.
To be replaceable, a method must also be wrappable.
For wrappable methods, you can opt in by adding [Replaceable] to the method.
see more details here: https://docs.microsoft.com/en-us/dynamics365/fin-ops-core/dev-itpro/extensibility/extensibility-attributes
Adding a new inventory dimensions using extension is easy now in D365
Hi Folks,
I was browsing for a concept where i need to add new inventory dimension to my customization and came to know that, Its pretty easy and simple now in Dynamics 365 using extension concept.
Please check out the link below for more details:
H@ppy D@xing...
Form implements interface concept now in D365
public class MyForm extends FormRun implements SysPackable
{
}
Below taking the example of to implement a method on each form part that is used on the workspace that would get a filter value from its parent workspace form and trigger those methods each time a modified() method is triggered on a workspace itself. However, this solution has two main issues.New capability in X++ : The In operator
private PriceAmountStdAdjustment calcPriceAmountStdAdjustment()
{
CustomSettlement customSettlement;
select sum(PriceAmountAdjustment) from customSettlement
where customSettlement.TransRecId == this.RecId
&& customSettlement.Cancelled == NoYes::No
&& (customSettlement.OperationsPosting == PostingType::PurchStdProfit
|| customSettlement.OperationsPosting == PostingType::PurchStdLoss
|| customSettlement.OperationsPosting == PostingType::InventStdProfit
|| customSettlement.OperationsPosting == PostingType::InventStdLoss)
;
return customSettlement.PriceAmountAdjustment;
}
It can now be refactored to support an extender in controlling which PostingTypes to include in the calculation:
private PriceAmountStdAdjustment calcPriceAmountStdAdjustment()
{
CustomSettlement customSettlement;
Container postingTypes = this. postingTypesForPriceAmtStdAdjustmentCalculation();
select sum(PriceAmountAdjustment) from customSettlement
where customSettlement.TransRecId == this.RecId
&& customSettlement.Cancelled == NoYes::No
&& (customSettlement.OperationsPosting in postingTypes ;
return customSettlement.PriceAmountAdjustment;
}
protector container postingTypesForPriceAmtStdAdjustmentCalculation()
{
return [PostingType::PurchStdProfit,
PostingType::PurchStdLoss,
PostingType::InventStdProfit,
PostingType::InventStdLoss];
}
Awesome feature but still most people didn't noticed.Chain of command on Form level are more flexible now in Dynamics 365
[ExtensionOf(formStr(SomeForm))]
[ExtensionOf(formControlStr(SomeForm, SomeControl))]
[ExtensionOf(formDataSourceStr(SomeForm, SomeDataSource))]
[ExtensionOf(formDataFieldStr(SomeForm, SomeDataSource, SomeField))]
See more links here: https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/extensibility/method-wrapping-coc