using Microsoft.Dynamics.AX.Framework.Utilities;
using Microsoft.Dynamics.ApplicationPlatform.Environment;
class M_DeepLinkCreator
{
/*#######################################################################################################################################*/
public static str createDeepLink(str _menuItemName, DataSourceName _dataSourceName, Map _fieldValuesMap, DataAreaId _dataAreaId = curExt())
{
IApplicationEnvironment env = EnvironmentFactory::GetApplicationEnvironment();
System.Uri host = new System.Uri(env.Infrastructure.HostUrl);
MapEnumerator mapEnumerator;
UrlHelper.UrlGenerator generator = new UrlHelper.UrlGenerator();
generator.HostUrl = host.GetLeftPart(System.UriPartial::Path);
generator.Company = _dataAreaId;
generator.MenuItemName = _menuItemName;
if (_dataSourceName && _fieldValuesMap)
{
mapEnumerator = _fieldValuesMap.getEnumerator();
var requestQueryParameterCollection = generator.RequestQueryParameterCollection;
while (mapEnumerator.moveNext())
{
requestQueryParameterCollection.UpdateOrAddEntry(_dataSourceName, mapEnumerator.currentKey(), mapEnumerator.currentValue());
}
}
return generator.GenerateFullUrl().AbsoluteUri;
}
/*#######################################################################################################################################*/
}
Hope it's going to be useful for you in your development process.
среда, 29 ноября 2023 г.
Open D365F&O form with specific query parameters in URL
Recently I was struggled with one task assigned to me. I had to store string as URL that points to the particular form with particular query filtered. For instance, open particular sales order or some voucher.
A colleguae of mine has proposed coming up with such a logic to generate deep link with all required parameters:
среда, 11 октября 2023 г.
Dynamics 365F&O different types of functions and classess
Just like a small reminder for those who might be forgetting it from time to time. Me personally find this piece of information pretty useful as a remark :-)
Functions:
Static Functions: These functions are tied to the class rather than an instance. They can be called without creating an instance of the class. They're commonly used for utility functions that don't rely on instance-specific data.
Instance Functions: These functions require an instance of the class to be invoked. They operate on the data that belongs to the object and are responsible for object-specific behavior.
Main Method: This is the entry point for class execution, usually for testing or batch processing. The main() method is static and can accept command-line arguments.
Final Functions: These are functions that cannot be overridden in derived classes. This ensures that the implementation of the function remains consistent.
Abstract Functions: These functions don't have any implementation in the base class. Derived classes must provide an implementation for these functions, making them ideal for defining a common interface.
Classes:
Table Classes: These classes directly represent tables in the AOT (Application Object Tree). They're automatically created and can be extended but not modified.
Form Classes: These are auto-generated when you create a form in the AOT. They contain methods that run form logic and control form events.
Data Provider Classes: Used primarily for SSRS reports, these classes gather the data that is then displayed on the report.
Framework Classes: These classes provide foundational structures for common functionalities. Classes like RunBase and RunBaseBatch are examples that provide a standardized way to create batch jobs or runnable classes.
Helper Classes: These are custom-defined classes that encapsulate shared logic or functionalities that can be reused across modules.
Controller Classes: These classes act as mediators in complex operations like reporting or batch processing, organizing the overall execution flow.
Contract Classes: These are used to encapsulate parameters for services or reports, making it easier to manage and validate the input.
Extension Classes: These allow you to add new methods to existing table, form, or class objects without altering the original codebase.
Attribute Classes: These are special classes that act as metadata, allowing you to tag elements in the code for additional behaviors or properties.
Map Classes: These simulate tables but don't involve data storage in the database. They're useful for temporary data manipulation tasks.
Special Classes:
Global Class: This class contains global methods and variables that can be accessed across the application, serving as a utility hub.
Application Classes: Classes like Info, ClassFactory, and Global that serve specific application-level functionalities.
Sys Classes: These are system-level classes such as SysDictTable, SysQuery, and SysFormRun. They are crucial for interacting with system-level functionalities and metadata.
Functions:
Static Functions: These functions are tied to the class rather than an instance. They can be called without creating an instance of the class. They're commonly used for utility functions that don't rely on instance-specific data.
Instance Functions: These functions require an instance of the class to be invoked. They operate on the data that belongs to the object and are responsible for object-specific behavior.
Main Method: This is the entry point for class execution, usually for testing or batch processing. The main() method is static and can accept command-line arguments.
Final Functions: These are functions that cannot be overridden in derived classes. This ensures that the implementation of the function remains consistent.
Abstract Functions: These functions don't have any implementation in the base class. Derived classes must provide an implementation for these functions, making them ideal for defining a common interface.
Classes:
Table Classes: These classes directly represent tables in the AOT (Application Object Tree). They're automatically created and can be extended but not modified.
Form Classes: These are auto-generated when you create a form in the AOT. They contain methods that run form logic and control form events.
Data Provider Classes: Used primarily for SSRS reports, these classes gather the data that is then displayed on the report.
Framework Classes: These classes provide foundational structures for common functionalities. Classes like RunBase and RunBaseBatch are examples that provide a standardized way to create batch jobs or runnable classes.
Helper Classes: These are custom-defined classes that encapsulate shared logic or functionalities that can be reused across modules.
Controller Classes: These classes act as mediators in complex operations like reporting or batch processing, organizing the overall execution flow.
Contract Classes: These are used to encapsulate parameters for services or reports, making it easier to manage and validate the input.
Extension Classes: These allow you to add new methods to existing table, form, or class objects without altering the original codebase.
Attribute Classes: These are special classes that act as metadata, allowing you to tag elements in the code for additional behaviors or properties.
Map Classes: These simulate tables but don't involve data storage in the database. They're useful for temporary data manipulation tasks.
Special Classes:
Global Class: This class contains global methods and variables that can be accessed across the application, serving as a utility hub.
Application Classes: Classes like Info, ClassFactory, and Global that serve specific application-level functionalities.
Sys Classes: These are system-level classes such as SysDictTable, SysQuery, and SysFormRun. They are crucial for interacting with system-level functionalities and metadata.
понедельник, 19 июня 2023 г.
Convert set to container X++
Recently I've faced with a task - I had two sets and I need to check item by item for both of them to identify number of common values.
Going with Enumerator or Iterator would be the obvious way. However, I wanted to eliminate of ambiguous code and found different way.
I converted SET to Container and checked elements one by one. Maybe it's not the best solution from performance standpoint (yes, I'm aware of slowness of containers), but it's the simplest one.
So, the actual conversion of the Set to Container I did via next code:
Set incomeSet = new Set(Types::String);
cntainer outputCon;
//filling in set.
outputCon = condel(incomeSet.pack(), 1,3);
The condel() funciton deletes all special symbols and other staff and in the end you'll get something like that:
вторник, 31 августа 2021 г.
Get the Enum name or value via SQL for D365F&O
Hello. Today I'm gonna show you how you can get the enum value based on the
enum name from D365F&O. Frequently, it's quite hard to find proper enum value
for some base enum, for example, InventTransType. And what if you know only the
system name, but not the Id or Label and you wanted to find it as quickly as
possible? Below you may find the SQL script to get all you need at once:
select t1.*, t2.* from ENUMIDTABLE t1 inner join ENUMVALUETABLE t2 on t1.ID=t2.ENUMID where t1.NAME='InventTransType'And here what you've got I hope that information will be useful for you. Happy DAXing!
среда, 25 ноября 2020 г.
SQL: get number of records for all tables in Database
Below you may find easist way to get number of records per table in your database. Sometimes it's extremely needed.
пятница, 2 октября 2020 г.
Get size of all tables in current database SQL
I have a task - to perform data upgrade from AX2012 to D365FO and I was wondering how big is each of the customer's table. I'm aware of Object explorer details(F7) in SQL Management studio but it works not fast as I'd like to. So I googled and found a bunch of different scripts that shows different information regarding your database.
One of that scripts I used and the result was pretty good. So I recommend you to use that script if you'd have the same task. The code is below:
SELECT
a2.name AS TableName,
a1.rows as [RowCount],
--(a1.reserved + ISNULL(a4.reserved,0)) * 8 AS ReservedSize_KB,
--a1.data * 8 AS DataSize_KB,
--(CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS IndexSize_KB,
--(CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS UnusedSize_KB,
CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_MB,
CAST(ROUND(a1.data * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_MB,
CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_MB,
CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_MB,
--'| |' Separator_MB_GB,
CAST(ROUND(((a1.reserved + ISNULL(a4.reserved,0)) * 8) / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS ReservedSize_GB,
CAST(ROUND(a1.data * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS DataSize_GB,
CAST(ROUND((CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS IndexSize_GB,
CAST(ROUND((CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 / 1024.00 / 1024.00, 2) AS NUMERIC(36, 2)) AS UnusedSize_GB
FROM
(SELECT
ps.object_id,
SUM (CASE WHEN (ps.index_id < 2) THEN row_count ELSE 0 END) AS [rows],
SUM (ps.reserved_page_count) AS reserved,
SUM (CASE
WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count)
ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count)
END
) AS data,
SUM (ps.used_page_count) AS used
FROM sys.dm_db_partition_stats ps
--===Remove the following comment for SQL Server 2014+
--WHERE ps.object_id NOT IN (SELECT object_id FROM sys.tables WHERE is_memory_optimized = 1)
GROUP BY ps.object_id) AS a1
LEFT OUTER JOIN
(SELECT
it.parent_id,
SUM(ps.reserved_page_count) AS reserved,
SUM(ps.used_page_count) AS used
FROM sys.dm_db_partition_stats ps
INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
WHERE it.internal_type IN (202,204)
GROUP BY it.parent_id) AS a4 ON (a4.parent_id = a1.object_id)
INNER JOIN sys.all_objects a2 ON ( a1.object_id = a2.object_id )
INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
WHERE a2.type <> N'S' and a2.type <> N'IT'
--AND a2.name = 'MyTable' --Filter for specific table
--ORDER BY a3.name, a2.name
ORDER BY ReservedSize_MB DESC
Just do the Copy-> Paste into your management studio and run in in front of the desirable database.вторник, 30 июля 2019 г.
How to filter record by dimension values in D365
It's been a long time I wrote the post in my blog. But today I will fresh it by writing the new one.
I got a task - to filter the query on worker's default dimension fields. This was quite challenging for me.
First I did it via DimensionAttributeValueSetStorage class. It didn't feet the requirement because the functionality has to have a possibility to filter records via any of the dimensions (Division, Location, CostCenter, Department, etc).
Next, I found an article about DimensionsProvider class which has some sort of abilities that I was needed. And I used it.
It worked as expected and as required!
So, below I provided a piece of code which you can interpret for your requirements, but I believe the general concept will be clear:
private void filterResourcesByDimensions(Query _q)
{
Counter i;
DimensionAttribute dimensionAttribute;
str dimValue;
container workerDefaultDimension, workerDefaultDimensionVal;
QueryBuildDataSource qbdsResource;
DimensionProvider dimProvider = new DimensionProvider();
workerDefaultDimension = ['Division', 'Location', 'Region', 'ServiceLine', 'SubService'];
workerDefaultDimensionVal = [_context.division(),
_context.location(),
_context.region(),
_context.serviceLine(),
_context.subService()
]; //Dimensions values (any)
qbdsResource = _q.dataSourceTable(tableNum(ResCompanyResourceView));
for (i = 1; i <= conLen(workerDefaultDimension); i++)
{
dimensionAttribute = dimensionAttribute::findByName(conPeek(workerDefaultDimension,i));
if (dimensionAttribute.RecId == 0 && conpeek(workerDefaultDimensionVal, i) == '')
{
continue;
}
dimValue = conPeek(workerDefaultDimensionVal,i);
if (dimValue != "")
{
dimProvider.addAttributeRangeToQuery(_q, qbdsResource.name(), identifierStr(DefaultDimension), DimensionComponent::DimensionAttribute, dimValue, dimensionAttribute.Name);
}
}
}
Feel free to contact if you still have any questions! I'm
вторник, 20 ноября 2018 г.
How to decode XML string Ax 2012
Hi again! I haven't written posts recently. But today I had a task, which was unusual for me - decode XML string to readable view to parse particular value. Or decoding the XML string.
So, I got a xml node like this
<column columnName="OrderLineFieldValues"><OrderLineFieldValueCollection><OrderLineFieldValue><OrderLineFieldSystemName>Backordered</OrderLineFieldSystemName><Value>4</Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>CutInspect</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>Mileage</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>Notes</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>SerialNumber</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue></OrderLineFieldValueCollection></column>';
So, looks a little bit confused, doesn't it?
Well, from this mess I'd need to get particular values. How can I do this? First of all, I started searching some sort of open API to do this but faced with lack of it. But after 1 hour or so I finally found the desired solution. For me it looks like this:
All that I need is in one HtmlDecode method! It's nice. Now I can continue working on the parser which could help me to get the required value from the XML node.
Hope, this piece of code would be useful for someone other as it was for me!
Happy DAXing!
So, I got a xml node like this
<column columnName="OrderLineFieldValues"><OrderLineFieldValueCollection><OrderLineFieldValue><OrderLineFieldSystemName>Backordered</OrderLineFieldSystemName><Value>4</Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>CutInspect</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>Mileage</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>Notes</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue><OrderLineFieldValue><OrderLineFieldSystemName>SerialNumber</OrderLineFieldSystemName><Value></Value></OrderLineFieldValue></OrderLineFieldValueCollection></column>';
So, looks a little bit confused, doesn't it?
Well, from this mess I'd need to get particular values. How can I do this? First of all, I started searching some sort of open API to do this but faced with lack of it. But after 1 hour or so I finally found the desired solution. For me it looks like this:
static void Job3(Args _args)
{
str output;
str input = @'my encoded XML string';
output = System.Web.HttpUtility::HtmlDecode(input);
info(output);
}
All that I need is in one HtmlDecode method! It's nice. Now I can continue working on the parser which could help me to get the required value from the XML node.
Hope, this piece of code would be useful for someone other as it was for me!
Happy DAXing!
среда, 5 сентября 2018 г.
Get LogisticsLocation record from customer
Hi!
Today I've had a requirement to show some custom fields from the LogisticsLocation record from the customer table. I wrote a display method for a particular field, but this approach can be used in different ways. It depends on your requirements.So, below the code:
public display IsReservedAccount displayIsReservedAccount(CustTable _customer)Hope it will be useful for someone as for myself.
{
DirParty dirParty;
LogisticsLocation location;
LogisticsPostalAddress address;
dirParty = DirParty::constructFromCommon(_customer);
address = dirParty.getPrimaryPostalAddressLocation().getPostalAddress();
location = LogisticsLocation::find(address.Location);
return location.IsReservedAccount;
}
пятница, 18 мая 2018 г.
Check how many rows were selected on the form grid
Hi!
This approach is common for either DAX 2012 or D365FO.
If you need to check how many rows were selected by the user, you just need to get the formDataSource value before, for example
FormDatasource fds = _args.record().datasource();
And then write next code:
Hope, this information will be useful for someone as for me.
This approach is common for either DAX 2012 or D365FO.
If you need to check how many rows were selected by the user, you just need to get the formDataSource value before, for example
FormDatasource fds = _args.record().datasource();
And then write next code:
if (fds.recordsMarked().lastIndex() > 1)
{
info("more than 1 record was selected");
}
Hope, this information will be useful for someone as for me.
понедельник, 12 марта 2018 г.
Disable auto complete of form control
Today I've faced with an issue which causes some discontent of my client. He wanted to scan barcode via barcode field but without autocomplete in this field. What I mean: when you input something into the field (the field type doesn't matter), the system "remembers" this value and if you try to enter it one more time when you started to enter, the system will complete it for you. For example:
"111". When you started entering 111 second time the system will finish it for you.
And I'd need to disable this feature as my client wants. But I didn't find any property which can help me with this.
After a while, my friend suggested I use the method delAutoCompleteString() on the control.
Finally, the code for disabling autocompletion for control would look like this:
public boolean modified()}
{boolean ret;
;
ret = super();
element.delAutoCompleteString(this);
return ret;
I hope, this information will be helpful for someone else :)
Happy DAX-ing!
пятница, 22 сентября 2017 г.
Check if ItemId is serialized
Hi folks!
Recently I've had a task in which I need to change visibility of particular button if Item number was serialized.
I found a way how to identify it by checking InventTrans statusReceipt.
But after that my colleague advised to me a way with checking Tracking Dimension Group and now I wanted to share this approach with you, guys!
Maybe it will be useful for someone in future.
Code below:
private boolean checkItemSerialized(ItemId _itemId)
{
EcoResTrackingDimensionGroupItem trackingDimensionGroupItem;
EcoResTrackingDimensionGroup trackingDimensionGroup;
boolean ret;
;
trackingDimensionGroupItem = EcoResTrackingDimensionGroupItem::findByItem(curext(), _itemId);
trackingDimensionGroup = EcoResTrackingDimensionGroup::find(trackingDimensionGroupItem.TrackingDimensionGroup);
if (trackingDimensionGroup.Name == #DimSerial)
{
ret = true;
}
return ret;
}
четверг, 10 августа 2017 г.
Get contact info from site address
Hi fellows!
Recently I h ave had some difficults to get contact information from Site address and I did searching at least 2 days.
I tried tu use many different approaches, some of them was to complicated, some not, but all was not working unfortunately.
But today I found working ( I guess) way.
Here's the code how to get contact information from site address (either phone, email, url and so on). For my case it was Phone:
LogisticsEntityPostalAddressView postalAddressView;
LogisticsElectronicAddress electronicAddress;
LogisticsLocation contactLocation;
inventLocation = inventLocation::find(ShipmentTable.InventLocationId);
if (inventLocation)
{
select firstonly postalAddressView
where postalAddressView.Entity == inventLocation.RecId
&& postalAddressView.EntityType == LogisticsLocationEntityType::Site
&& postalAddressView.isPrimary == NoYes::Yes;
if (postalAddressView)
{
select firstOnly electronicAddress where electronicAddress.Type == LogisticsElectronicAddressMethodType::Phone
join contactLocation where contactLocation.ParentLocation == postalAddressView.Location
&& contactLocation.RecId == electronicAddress.Location;
info(strFmt("Primary contact name: %1 Primary contact phone: %2",electronicAddress.Description, electronicAddress.Locator));
}
I tried and it worked! I improved query, because originally it has 2 selects instead of 1.
Hope it will be useful for someone!
Happy DAX-ing. :)
четверг, 6 июля 2017 г.
Update/delete InventDim (memorize)
Recently I've found during searching one interesting information that could be useful for anyone who develops in AX.
The information related to manipulation with data in InventDim table.
InventDim table is backbone of Dynamics AX Inventory management module
before deleting inventDim record using method inventDim.delete(true) you should do following validation
* There should not be any record in InventSum table related the InventDimID which you are going to delete
* There shuld not be any record in InventTrans table related to InventDimID whicu you are going to delete
before updating inventDIM record using method inventDim.update(true) you should do following validation
* ensure that inventTrans records related to inventDimID which is getting updated is good to get updated with new 'inventBatchId' and 'InventSerialId', otherwise you will have bad information is On-hand details
* ensure that inventDim table is not having any record with new combination is inventory dimension, otherwise it will not get update.
It is recommended that we should not do any outside update and delete in InventDim Table, but if you will take care of above data intigrity checks then you can update and delete the records in InventDim Table with out any issue.
I hope these observations will be helpful :)
Happy DAX-ing !
понедельник, 27 марта 2017 г.
How to extend BaseEnum Ax7
Today I had some misunderstanding of extension concept. I just wanted to create an extension of NumberSequence, but couldn't do it.
After some investigation I found out that only those BaseEnums which have IsExtendible propety set to true are allowed to extend.
So bear this info in mind during create own enums or extensions from standard enums :)
Happy DAX-ing!
After some investigation I found out that only those BaseEnums which have IsExtendible propety set to true are allowed to extend.
So bear this info in mind during create own enums or extensions from standard enums :)
Happy DAX-ing!
среда, 15 марта 2017 г.
Remove "Close" button from form
Hi All!
Today I found that I fogrot how the Close button could be hidden from standard AX form.
But after google helped me and I share with you this information:
All you need to do is set the "Status bar style" property to SimpleWithoutClose.
And that's it :) Profit.
Today I found that I fogrot how the Close button could be hidden from standard AX form.
But after google helped me and I share with you this information:
All you need to do is set the "Status bar style" property to SimpleWithoutClose.
And that's it :) Profit.
воскресенье, 26 февраля 2017 г.
Event handler for form datasource ax7
Hi, dear readers!
Recently I've had new task for Ax7, namely, I had to change behavior of one control on form. For this I must not customize current form, but extend it and create event handler to handle it. This was I done.
And below I just wanted to share with you some thoughts about how we could do it faster and easier:
[FormDataSourceEventHandler(formDataSourceStr(WHSShipmentDetails, WHSShipmentTable), FormDataSourceEventType::Activated)]
public static void WHSShipmentTable_OnActivated(FormDataSource sender, FormDataSourceEventArgs e)
{
WHSShipmentTable shipmentTable = sender.cursor(); // our Args.record()
//FormDataSource shipmentDs = sender.formRun().dataSource(tableNum(WHSShipmentTable)); // in that way we could get DataSource to manipulate ds fields for example.
FormControl printConfirmControl = sender.formRun().design(0).controlName("ConfirmAndPrintShipmentRun"); //get control to change behavior
printConfirmControl.enabled(WHSShipConfirm::isShipConfirmEnabledForShipment(shipmentTable));
}
After creating new class, build the project and verify whether your event handler works or not.
Hope it'd be helpful!
Looking forward to seeing with you in new posts!
Recently I've had new task for Ax7, namely, I had to change behavior of one control on form. For this I must not customize current form, but extend it and create event handler to handle it. This was I done.
And below I just wanted to share with you some thoughts about how we could do it faster and easier:
[FormDataSourceEventHandler(formDataSourceStr(WHSShipmentDetails, WHSShipmentTable), FormDataSourceEventType::Activated)]
public static void WHSShipmentTable_OnActivated(FormDataSource sender, FormDataSourceEventArgs e)
{
WHSShipmentTable shipmentTable = sender.cursor(); // our Args.record()
//FormDataSource shipmentDs = sender.formRun().dataSource(tableNum(WHSShipmentTable)); // in that way we could get DataSource to manipulate ds fields for example.
FormControl printConfirmControl = sender.formRun().design(0).controlName("ConfirmAndPrintShipmentRun"); //get control to change behavior
printConfirmControl.enabled(WHSShipConfirm::isShipConfirmEnabledForShipment(shipmentTable));
}
After creating new class, build the project and verify whether your event handler works or not.
Hope it'd be helpful!
Looking forward to seeing with you in new posts!
среда, 28 декабря 2016 г.
How to run client with particular AOS
Recently I had a task to run AX with particular AOS on the same machine. It has 2 aos installed.
But I don't have access to Configuration utility.
So, I thought that there's a way to run ax without shortcut, but with cmd.
I goggle and found a solution which works exactly I need:
1. Open cmd (no matter with Administration privilegy or without).
2. Go to C:\Program Files (x86)\Microsoft Dynamics AX\50\Client\Bin (the path may be different , it depends on Ax version.
3. Run AX32.exe with following parameters:
-loadbalance=0 -aos2 = "your aos instance name"
4. Press Enter.
Profit!
вторник, 4 октября 2016 г.
How to add new document into print management module
Hi All!
Recently I've faced with task which I've never done before. It's adding new document into print managment settings for certain module (in my case it was WHS module).
I tried to found any solution or advice in web but it was unsuccessfully.
Finally I found some advice regarding my issue but is was written not so good as for me.
And I decided to keep this solution in my blog so here're we go:
Lets asume that we want to add new document with "DocName" into our print management settings.
What we should do for this?
After that you could see your document under WHS print management module settings.
But the thing is you won't be able to add Report format value untill add it into PrintMgmtReportFormat table manually (I haven't explanation of this yet).
After you added the value into this table - you'll be able to print your report.
Profit!
Recently I've faced with task which I've never done before. It's adding new document into print managment settings for certain module (in my case it was WHS module).
I tried to found any solution or advice in web but it was unsuccessfully.
Finally I found some advice regarding my issue but is was written not so good as for me.
And I decided to keep this solution in my blog so here're we go:
Lets asume that we want to add new document with "DocName" into our print management settings.
What we should do for this?
1) Go to Data Dictionary -> Base enums -> and find PrintMgmtDocType.
2) Add new enum into this base enum with name "DocName"
3) Go to Classes -> PrintMgmtDocType
4) Find method getDefaultReportFormat() in this class and add new case statement into it for our enum
5) Add appropriate tableId and FieldId into getQueryRangeFields() and getQueryTableId() methods for further treatment
6) Next, add a case statement to the method getDocumentTypes() of the class PrintMgmtNode child class, i.e. PrintMgmtNode_CustTable or PrintMgmtNode_Sales or whichever node you want to add it to in the print management hierarchy. In our situation it was class WHSPrintMgmtNode_WHS.
After that you could see your document under WHS print management module settings.
But the thing is you won't be able to add Report format value untill add it into PrintMgmtReportFormat table manually (I haven't explanation of this yet).
After you added the value into this table - you'll be able to print your report.
Profit!
Подписаться на:
Сообщения (Atom)

