Tuesday, 5 December 2017

creation of test class method by using detourContext in d 365

Hi all my invent table has following update method has following code :

       super()

        if (this.PhysicalDimensionInventoryUnitOfMeasure(this_Orig))
        {
            this.DimensionInventoryUnitOfMeasure();
        }

now we can create 2 test class method in inventtabletest using de detour   build the project and run the test method both will get passed.

:



    // <summary>
    /// Tests shouldUpdatePhysicalDimensionInventoryUnitOfMeasure method returns false if inventory net weight is not updated.
    /// </summary>
    [SysTestMethod]
    public void update_ShouldUpdatePhysicalDimensionInventoryTrue_PhyscialDimUpdated()
    {
        ttsbegin;
        using (var detourContext = SysDetourContext::createContext())
        {
            // Arrange
            detourContext.whenMethodCalled(
                UtilElementType::Table,
                tableStr(InventTable),
                tableMethodStr(InventTable, shouldUpdatePhysicalDimensionInventoryUnitOfMeasure))
            .doReturnValue(true);
            WHSPhysDimUOM   WHSPhysDimUOM;
            WHSPhysDimUOM.Width     = 0;
            WHSPhysDimUOM.UOM       = InventTableModule::find(inventTable.ItemId, ModuleInventPurchSales::Invent).UnitId;
            WHSPhysDimUOM.ItemId    = inventTable.ItemId;
            WHSPhysDimUOM.Depth     = 0;
            WHSPhysDimUOM.Height    = 0;
            WHSPhysDimUOM.doInsert();
            inventTable.selectForUpdate(true);
            inventTable.grossDepth  = 10;
            inventTable.grossHeight = 20;
            inventTable.grossWidth  = 30;
            inventTable.TaraWeight  = 10;
            inventTable.NetWeight   = 20;
            //inventTable.update();
            // Act
            inventtable.update();
            WHSPhysDimUOM.reread();
            // Assert
            this.assertEquals(inventTable.grossDepth, WHSPhysDimUOM.Depth, 'The depth value of physical dimension table should match with grossDepth of inventory table.');
            this.assertEquals(inventTable.grossHeight, WHSPhysDimUOM.Height, 'The height value of physical dimension table should match with grossHeight of inventory table.');
            this.assertEquals(inventTable.grossWidth, WHSPhysDimUOM.Width, 'The width value of physical dimension table should match with grossWidth of inventory table.');
            this.assertEquals(inventTable.grossWeight(), WHSPhysDimUOM.Weight, 'The weight value of physical dimension table should match with grossWeight of inventory table.');
        }
        ttsabort;
    }
    // <summary>
    /// Tests shouldUpdatePhysicalDimensionInventoryUnitOfMeasure method returns false if inventory net weight is not updated.
    /// </summary>
    [SysTestMethod]
    public void update_ShouldUpdatePhysicalDimensionInventoryTrue_PhyscialDimNotUpdated()
    {
        ttsbegin;
        using (var detourContext = SysDetourContext::createContext())
        {
            // Arrange
            detourContext.whenMethodCalled(
                UtilElementType::Table,
                tableStr(InventTable),
                tableMethodStr(InventTable, shouldUpdatePhysicalDimensionInventoryUnitOfMeasure))
            .doReturnValue(false);
            WHSPhysDimUOM   WHSPhysDimUOM;
            WHSPhysDimUOM.Width     = 0;
            WHSPhysDimUOM.UOM       = InventTableModule::find(inventTable.ItemId, ModuleInventPurchSales::Invent).UnitId;
            WHSPhysDimUOM.ItemId    = inventTable.ItemId;
            WHSPhysDimUOM.Depth     = 0;
            WHSPhysDimUOM.Height    = 0;
            WHSPhysDimUOM.doInsert();
            inventTable.selectForUpdate(true);
            inventTable.grossDepth  = 10;
            inventTable.grossHeight = 20;
            inventTable.grossWidth  = 30;
            inventTable.TaraWeight  = 10;
            inventTable.NetWeight   = 20;       
            // Act
            inventtable.update();
            WHSPhysDimUOM.reread();
            // Assert
            this.assertNotEqual(inventTable.grossDepth, WHSPhysDimUOM.Depth, 'The depth value of physical dimension table should not match with grossDepth of inventory table.');
            this.assertNotEqual(inventTable.grossHeight, WHSPhysDimUOM.Height, 'The height value of physical dimension table should not match with grossHeight of inventory table.');
            this.assertNotEqual(inventTable.grossWidth, WHSPhysDimUOM.Width, 'The width value of physical dimension table should not match with grossWidth of inventory table.');
            this.assertNotEqual(inventTable.grossWeight(), WHSPhysDimUOM.Weight, 'The weight value of physical dimension table should not match with grossWeight of inventory table.');
        }
        ttsabort;
    }

all report deployment for powershell in d 365


Open windows powershell in administrator mode.
execute below comments


1.paste the "Set-ExecutionPolicy Unrestricted" instructions
2. then select  "Y" for yes.
3. paste the below instructions


C:\AosService\PackagesLocalDirectory\Plugins\AxReportVmRoleStartupTask\DeployAllReportsToSSRS.ps1 -PackageInstallLocation “C:\AosService\PackagesLocalDirectory”

Tuesday, 14 November 2017

import DPK in d365 and add move all the objects in a single project.

paste the DPK file in the rainmain folder of rainmain drive.

then open the corext rainmain(run as administrator).

run the below syntax.

sdp apply unittesttart.dpk -a

please note - unittesttart.dpk is the name of DPK.


If you open SDB, you can see that a new change list has been created. 

then open the dev environment.


click on d365 in the tool bar.>>add ins>>create project from change list.

it will include all the objects from the single change list in one project no need to drag and drop each objects in the projects.



Monday, 23 October 2017

creation of test case and running it sucessfully

Please create a new test case in class WHSPhysDimUOMScenarioTest   right click the test and click run


    /// <summary>
    /// Tests that when the isAnyPhysicalDimensionDifferentThanItemInventoryPhysicalDimension  is   called with a different
    /// Depth in inventory physical dimension unit of measure and physical dimension unit of measure,
    /// then the returned type will be true.
    /// </summary>
    [SysTestMethod]
    public void isPhysicalDimensionsDistinctThanInventoryDimension_DiffrentUOMFound_returnFalse()
    {
        WHSPhysDimUOM   WHSPhysDimUOM;
        boolean         ret = false;
       
        ttsbegin;
        // Arrange
        select forupdate item;
        item.grossDepth  = 10;
        item.grossHeight = 25;
        item.grossWidth  = 30;
        item.TaraWeight  = 10;
        item.NetWeight   = 20;
        item.doUpdate();
        WHSPhysDimUOM.UOM       = '';
        WHSPhysDimUOM.ItemId    = item.ItemId;
        WHSPhysDimUOM.Depth     = 10;
        WHSPhysDimUOM.Height    = 25;
        WHSPhysDimUOM.Width     = 30;
        WHSPhysDimUOM.Weight    = 30;
        WHSPhysDimUOM.doInsert();
        // Act
        ret = WHSPhysDimUOM.isAnyPhysicalDimensionDifferentThanItemInventoryPhysicalDimension();
        WHSPhysDimUOM.reread();
        // Assert
        this.assertEquals(ret, false, 'The item inventory physical dimension is different for the physical dimesnsion.');
        ttsabort;
    }

Saturday, 21 October 2017

xppcAgent in d365

when ever we do build in D365 then normally it takes minutes to load the form in AX .

we can some thing to make it work faster

1.disable best practice check

2.We should kill Xppc Agent in task manager.



normally when we do build this starts in work and as build gets over  please go to the task manager and kill the specified task.

then the form will get loaded faster

but please make sure you do this after build is over other wise build will not het completed.


useful links for AX 7

catch the tts level in the catch


Sometimes when ever we are getting some error regarding the ttscommit level aborted , there we need to catch the ttsimbalance in the try catch.

catch (Exception::UpdateConflict)
        {
            if (appl.ttsLevel() != 0)
            {
                throw Exception::UpdateConflict;
            }
            this.myLogMethod();
        }


disable the form datasource from the class.

We can easily disable the form datasource from the class.

Practically there should be no code in the form except calling the methods all the codes should ne on form or tables.

lets have this code in form datasource active and modified method :

[DataSource]
    class WHSPhysDimUOM
    {
        public int active()
        {
            int ret = super();

            whsPhysDimUOMForm.setAllowEditPhysicalDimUOMDataSourc(WHSPhysDimUOM_ds);
                     
            return ret;
        }
        [DataField]
        class UOM
        {
            public void modified()
            {
                super();
                whsPhysDimUOMForm.setAllowEditPhysicalDimUOMDataSource(WHSPhysDimUOM_ds);
            }
        }
    }


Now go to the class write the code as :

    /// <summary>
    /// Sets the allow edit property for the passed <c>WHSPhysDimUOM</c> form data source.
    /// The passed data source must be <c>WHSPhysDimUOM</c>.
    /// </summary>
    public void setAllowEditPhysicalDimUOMDataSource(FormDataSource _formDataSource)
    {
        if (_formDataSource.cursor() is WHSPhysDimUOM)
        {
            WHSPhysDimUOM physDimUOM = _formDataSource.cursor();
            _formDataSource.allowEdit(!physDimUOM.isUnitSameAsItemInventoryUnit());
        }
        else
        {
            throw error(Error::wrongUseOfFunction(funcName()));
        }
    }



write the code in the table  :


    /// <summary>
    /// Checks if the unit is the same as the item's inventory unit, if the item is set.
    /// </summary>
    /// <returns>true, if the unit is the same as the item's inventory unit and the item is set; otherwise false.</returns>
    public boolean isUnitSameAsItemInventoryUnit()
    {
        return (this.ItemId
                && this.UOM == InventTableModule::find(this.ItemId, ModuleInventPurchSales::Invent).UnitId);
    }

Tuesday, 26 September 2017

pointing the record to the current record(positionToRecord)

public void executeQuery()
        {
            qbrLoad.value(loadId);
            super();
            if (detailUnmatched)
            {
                element.args().lookupRecord(TMSFreightBillDetail::find(detailUnmatched.FreightBillRecId));
                tmsFreightBillDetail_ds.research(false);
            }
        }


it will give infinite loop.


try like below :

if (detailUnmatched)
{
    tmsFreightBillDetail_ds.positionToRecord(TMSFreightBillDetail::find(detailUnmatched.FreightBillRecId));
}

http://happydev/Teams/Client/Pages/Code%20Migration%20-%20FindRecord%20FindValue.docx



Code Migration – findRecord and findValue methods on FormDataSource




Overview


The findRecord(Common record) method finds a specific record in the data source and makes it the current record.

The findValue(FieldId field, str value) method find a specific value in a specific field in the data source and makes the corresponding record the current record. It uses the findRecord method for this.

The problem with these methods is that they use linear searching. This causes a large number of records to be loaded in memory and impacts performance.

Replacement APIs – positionToRecord and positionToRecordByValue


The framework team has made available replacement APIs for the findRecord and findValue methods. The new APIs have the same signature as the old APIs to ensure easy migration but work differently under the covers. Also note that while we expect these to cover most cases there are limitations (details below).

·         public boolean positionToRecord(Common _record)

Replacement for: public boolean findRecord(Common _record)



·         public boolean positionToRecordByValue(FieldId _field, str _value)

Replacement for: public boolean findValue(FieldId _field, str _value)

Details and Limitations of replacement APIs


The new APIs first try and look for the record in the cache. This part works without any restrictions on the underlying data sources. However if the record cannot be found in the cache the APIs will try to use positioning as long as the underlying data sources support it.

Some cases where positioning and therefore the APIs do not work are:

                     When a View is being used as a data source

                     When a Temp Table is being used as a data source

                     When a Union Query is being used

                     If firstOnly is being used

                     If an Order By does not exist

                     If all data sources (QueryBuildDataSource) are set as enabled = false

To keep things simple we have designed the API to always throw an exception when the underlying data source does not support positioning, even if the record is in the cache.



Migration


                     A fixer is being written by the Client team to replace all calls in supported scenarios to new APIs.

o   3650174: FindRecord/FindValue - Create upgrade rule/fixer

o   3650176: FindRecord/FindValue - Run upgrade rule/fixer

                     Application teams need to manually investigate and migrate the occurrences remaining after the fixer has been run.

                     Application teams will also need to migrate any findRecord and findValue override methods.

                     For cases where the new APIs do not work you could try using

o    element.args().lookupRecord(recordToFind) Followed by

o    FormDataSource.research(false);

FormDataSource is the data source that contains the record you want to find. Passing in a “false” argument to research causes it to not retain the current position since we want to change the position to the record we found using args.lookupRecord. It also avoids resetting sort order, ranges, etc.



Old Migration Notes from Application Teams


Note: These notes pre-date the introduction of the positionToRecord and positionToRecordByValue APIs and are kept here for reference only. You should try and use positionToRecord and positionToRecordByValue first. If that does not work for your scenario you could try one of the solutions listed here to see if it helps.

Pattern
Explanation
Solution
Lookup form
The form tries to find the record that the caller supplied via args.record()
Set args.lookupRecord() when opening the form.
Tmp = current.data();
DS.ExecuteQuery();
DS.FindRecord(tmp);


An action is triggered that updates/adds/removes multiple records other than the active record, and the form needs to be refreshed to show the new set of records while retaining position
Call DS.research(true)

The true argument tells the framework to retain current position.
An action is triggered that updates/adds/removes multiple records in a linked datasource, and the form needs to be refreshed to show the new set of records while retaining position.
Call research() on the linked datasource instead of main datasource. Consider research(true) if position should be retained in the linked datasource as well.
Tmp = current.data();
DS.research();
DS.FindRecord(tmp);
To refresh the current record, e.g. from a caller

element.doResearch();
Temporary records
Temporary records are recreated and form needs to find the same (but not identical) record after pointing form at new set of records
To be determined
Loop: FindValue+MarkRecord

To be determined
Using FindRecord() to find a record in root datasource

Element.args().lookupRecord(the record to find);
DS.research(false)

Note that this will cause the pagination to start with this record like in a lookup form, so even if there are only a few records, some of those records may be hidden from the user until the user pages left.
Using FindRecord() to find a record in an active/passive joined datasource
A form has 2 datasources: headerTable and lineTable. FindRecord is used on the lineTable instead of the parent table.

For instance, the ProjInvoiceJournal form supports a special case of lookup, where the form is called from a project transaction. In this case, the ProjInvoiceJournal form will show the invoice in which the transaction was billed, and also move to the specific invoice line that billed the calling transaction.

Another use case is in TrvExpenses. When an employee files an expense report, some expense types, like Hotel, may require an itemization of values. In this case, a table is shown and the user may declare how much was spent on each sub category (Room rate, laundry, internet, ..) per day. An itemization for a long stay may contain 50-100 entries. Each cell has its own RecId. When the user tries to edit/clear a cell value, findValue() is used to move the DS cursor to the desired record for update. Contact: pevezzac

Repro steps:
1.       In USSI
2.       Open Expense management > Common > My expenses > Expense reports
3.       Select the record 000030, Conference and click Expense lines
4.       In the hotel line, click Edit and open the Itemize tab
5.       Change the cell (Daily room rate; Tue, 26, Jan) value to 50
6.       Change the cell (Daily room rate; Tue, 27, Jan) value to 50
7.       Hit Save
Expected: The bottom of the page shows: Itemized cost = 410, Remaining = 40
To be determined. LookupRecord() + research(false) only works on root datasources. A solution is needed for the child datasource scenario.
Using findRecord/findValue for datasource bound to a view.
When the datasource is bound to a view it is losing the ordering on the query when using the lookupRecord/research replacement pattern. 

Need the ability to bind to a view sorted by the natural key of the view, such as a Name field, and then be able to find records without losing the query ordering.

Repro steps:
1.       Click New
2.       Enter the name New in the drop dialog and click Create
Expected:
The list is updated to show the New record and the record is selected in the list.




Additional notes on args.lookupRecord() + research(false) in a non-lookup scenario

 this will cause the pagination to start at the record set in lookup record, which may be confusing if there are multiple records, as the user might have the middle record selected and then afterwards, the top record (the same record) is now selected and a different set of records are in practice shown on the screen.


Tuesday, 22 August 2017

how to add a label in d 365

always add label in label fields and help text.


1. go to label in AOT
2. drag the label which you want to edit in your project.
3.right click on the label and click open
4.click new and add label ID , label and description.
5. save the label
6.go to the field and like on search button and paste the label which you made right now and you might get many search results.

7.select the newly created label ID and click on paste.

best pratcise for assigning constant in d365

                               

                                numLP       = pass.lookupNum(#Qty);
                                const int userfinalQty = 1;       //declare the variable where it is needed to be used
                                finalQty    = userfinalQty;
                                finalUnitId = any2str(pass.lookup(#UOM));
                                pass.insert(#QtyReceived, numLP);

process of receiving transfer order in d 365

go to inventory management and click on transfer order and create a new transfer order

from warehouse 11
to warehouse 24

select item as A1 reserve all

click on generate picking list

select update all and click ok

then click on picking list registration  and select the line and click on update all


then refresh the page and click on ship transfer order


log in to the mobile device using user name and password and go to the inbound and click on transfer receive








Monday, 21 August 2017

classes used during purchase recieve and transfer receieve in Advance warehouse management

for transfer order receiving(advance warehouse management) in the mobile application

WhsWorkExecuteDisplayTOReceiving << displayform

for purchase order receiving(advance warehouse management) in the mobile application

WHSWorkExecuteDisplayPOReceiving<<displayform

debugging in d365

following settings are needed to be made so that code debugging can be done





Thursday, 17 August 2017

Restore clean Demo data



  1. Open SQL Server Management Studio 
  2. Create new query on the top node 
  1. Run the following query 

DECLARE @DatabaseName nvarchar(50) 
SET @DatabaseName = N'AxDBRAIN' 

DECLARE @SQL varchar(max) 
SET @SQL = '' 

SELECT @SQL = @SQL + 'Kill ' + Convert(varchar, SPId) + ';' 
FROM MASTER..SysProcesses 
WHERE DBId = DB_ID(@DatabaseName) AND SPId <> @@SPId 

EXEC(@SQL) 

-- Restore snapshot 
restore database AxDBRAIN from Database_snapshot = 'AxDBRAINInitialDataState' 

  1. If you can't login after this, then run the following script: 
update USERINFO 
set SID = 'S-1-19-1389536940-3857197118-2727713988-698496524-3874995910-1598698826-400483830-1280886117-2147114868-3359996204', 
NETWORKDOMAIN = 'https://sts.windows-ppe.net/', 
NETWORKALIAS  = 'tusr1@TAEOfficial.ccsctp.net ', 
IDENTITYPROVIDER = 'https://sts.windows-ppe.net/' 
where ID = 'Admin' 
and Partition = '5637144576'

intercompany PO multiple product receipt by x++

public void processStampICPO(PackingSlipId _deliveryNote,                             Transdate _deliverydate,                             ...