Tuesday, October 14, 2014

DIXF timeout issues

DIXF - Interesting find

I spent the past 2 weeks doing data migration and here are some interesting errors I found and how to fix them:

Several issues can be seen with large amounts of records (more than 200k - 300k) and medium amounts of records (around 200k) with a lot of data.
Here is the error:

System.ServiceModel.CommunicationException: An error occurred while receiving the HTTP response to http://myServer:7000/DMFService/DMFServiceHelper.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details. ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive. ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host 
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) 
--- End of inner exception stack trace --- 
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) 
at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size) 
at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead) 
--- End of inner exception stack trace --- 
at System.Net.HttpWebRequest.GetResponse() 
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) 
--- End of inner exception stack trace --- 

Server stack trace: 
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason) 
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) 
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) 
at System.ServiceModel.Channels.ClientReliableChannelBinder`1.RequestClientReliableChannelBinder`1.OnRequest(TRequestChannel channel, Message message, TimeSpan timeout, MaskingMode maskingMode) 
at System.ServiceModel.Channels.ClientReliableChannelBinder`1.Request(Message message, TimeSpan timeout, MaskingMode maskingMode) 
at System.ServiceModel.Security.SecuritySessionClientSettings`1.SecurityRequestSessionChannel.Request(Message message, TimeSpan timeout) 
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) 
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) 
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) 

Exception rethrown at [0]: 
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 
at Microsoft.Dynamics.AX.Framework.Tools.DMF.ServiceProxy.DMFServiceReference.ServiceContract.ShowPreview(DMFEntity entity) 
at Microsoft.Dynamics.AX.Framework.Tools.DMF.ServiceProxy.DmfEntityProxy.DoWork[T](Func`1 work)


We solve this by adding 'recieveTimeout' and 'sendTimeout' into the C:\Program Files\Microsoft Dynamics AX\60\DataImportExportFramework/Microsoft.Dynamics.AX.Framework.Tools.DMF.SSISHelperService.exe.config


<bindings>
      <wsHttpBinding>
        <binding name="DMFService_WsHttpBinding" receiveTimeout="01:00:00"
sendTimeout="01:00:00"
          maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
            maxArrayLength="2147483647" maxBytesPerRead="2147483647"             maxNameTableCharCount="2147483647" />
        </binding>
      </wsHttpBinding>
    </bindings>

Thursday, September 18, 2014

Check if user has access set up on a menu item

Recently I was working on a project where I needed to check if the user had security access to a Menu Item.  The menu item wasn't being used, but it had the security access that I wanted to check.

Very simply, I was able to use this:

Global::hasMenuItemAccess(...);

Worked great!

Thursday, August 14, 2014

Recently I was working on a project where I was calling into a class and I needed to verify the record that was coming in.  Here is how I did it:

public static void main(Args _args)
{
    MyClass                                myClass;
    RefRecId                                bankChequeTableRecId;
    FormDataSource                          formDataSource;
    ;

    myClass= MyClass::construct();
    if (_args != null && _args.dataSet() == tablenum(BankChequeTable) && _args.record().RecId != 0)
    {
        BankChequeTableRecId = _args.record().RecId;
        if (_args.record().IsFormDataSource() == true)
        {
            FormDataSource = _args.record().dataSource();
        }
    }
    if (BankChequeTableRecId != 0)
    {
        myClass.ToggleEditForAvidSync(BankChequeTableRecId);
    }
    if (formDataSource != null)
    {
        FormDataSource.research(true);
    }
}

Basically I am checking
1. _args has something
2. _args.dataSet() - Checking if this args is a BankChequeTable record
3. _args.record().RecId - Making sure there is a record in the args
4. Setting my RecId variable to the recid passed in by args.
5. _args.record().IsFormDataSource() - I want to know if this is a form data source and later one refresh that datasource.

I have needed this a lot so I thought I would post it up!

Friday, July 18, 2014

Add new Financial Dimension backing entity

Under General ledger -> Setup -> Financial dimensions, open the Financial dimensions form.  If you create a new dimension there is a list of 'Use values from'.  These are the backing entities that you can use values from.  I had a project to add something to this list.  

Rather than type everything out, here is the link to a post I found that gives a perfect description of how to accomplish this. 

Thanks!

Wednesday, June 18, 2014

SalesLine and Financial Dimensions

I was working with the SalesLine recently and needed a custom Financial Dimension added.  I found this great blog post that explains exactly how to do it:

http://www.intergen.co.nz/blog/tim-schofield/dates/2011/12/how-to-add-a-financial-dimension-in-ax-2012/


Wednesday, May 14, 2014

AX 2009 Compare form colors

I have been working a bit in AX 2009 lately and have found that the colors when comparing two objects, do not work.  A quick google search turned up this blog post:


Very good explanation of why and how to fix it. 

Thursday, April 3, 2014

Cheque_US printing 2 pages

I have been working with this report for some time now.  The idea here was that we needed the cheque to print at the BOTTOM of the page, which, according to microsoft should be really easy!

http://technet.microsoft.com/en-us/library/gg230993.aspx

Needless to say, the settings on this page didn't work.  If I tried to use the 'Check start position' to place the check on the page where I needed it, it would throw an error saying 'The starting position of the check is too far down the page.'  
The other potential solution was to just make the page longer, but then we got 2 pages printing with the 2nd page being blank!

GRRRRRR!

Finally I started digging and found out that the report has 'SlipTxt' boxes at the TOP and the BOTTOM of the report.  This is so that you can have your check print on either end and still have a stub.


From what I can tell, although the bottom 2 text boxes were 'Invisible' they still took up space and forced the printing of a second page.
Once I removed those, half of the battle was won.

The other thing I had to figure out was why I couldn't use the 'Check start position' on the check setup form to push the check further down the page.  BTW, These settings can be found in Cash and bank management -> Common -> Bank accounts -> Set up -> Check


To allow higher numbers such as 8.75 and such, you need to dig into the code in TWO places.  That's right, two places.  The 'Print test' you see here has it's own class where is the 'Generate payments' in the Payment journal lines has another class

Print Test - Classes\BankPrintTestCheque\getDocLength
Generate Payments - Classes\CustVendCheque\slipTxtLines

You will notice that you see a switch statement in each of them that looks like this:
 switch (_chequeFormType)
    {
        case ChequeFormType::USStyle,
            ChequeFormType::UKStyle,
            ChequeFormType::ESStyle,
            ChequeFormType::MXStyle,
            ChequeFormType::CAStyle,
            ChequeFormType::FRStyle :            
            chequeDocMm = 88.89;          
            break;
...
...

To allow larger numbers, you will need to change the 88.89 to something much lower.  I did mine to 18.89 and that seemed to be good enough to do what I wanted.

Good luck!



Thursday, March 20, 2014

Barcode on a SSRS Report

Recently I was tasked with adding a barcode to the SalesPackingSlip report.  I had never done a barcode before so I wasn't really sure how this would turn out.

To help me out, I used WMSPickingList_OrderPick as an example.

The first thing we want to do here is create some parameters for the CustFormLetterDocument and the corresponding form. You can get to this form by going Accounts receivable -> Setup -> Forms -> Form setup.  We want to add 2 parameters to the Packing slip section.

As you can see I have added two parameters.  One is the 'Bar code setup', which contains the Font, Font size, and other information that will help the report display the bar code the way you want.  The other is just in case the customer would like to not display the barcode on the report.

The next thing we want to do is add some fields to our SalesPackingSlipHeaderTmp.  I picked the Header tmp table because my barcode will be the PackingSlipId which will, of course, be in the header.
Add the following fields:

  BarCode of type BarCodeString
  BarcodeFontName of type FontName
  BarcodeFontSize of type FontSize

I think the BarCodeString field is obvious, but why the other two?  Well, we want to be able to get the information from the BarCode setup.  So, if the customer wants to change the barcode font or size, the report doesn't have to be changed.

Now we need to modify some code.  The SalesPackingSlipDP class is where we will do all these modifications.  First we start by declaring some class level variables:

    BarcodeSetupId                      barcodeSetupId;
    BarcodeSetup                         barcodeSetup;
    Barcode                                 barcode;
    NoYes                                   showBarcode;

As we use these variables, I will explain what they are used for.
First, we are going to create a method to initialize these variables.

private void initBarcode()
{
    showBarcode     = CustFormletterDocument::find().showPackingSlilpIdBarCode;
    barcodeSetupId  = CustFormletterDocument::find().barcodeSetupId;
    barcodeSetup    = BarcodeSetup::find(barcodeSetupId);
    barcode         = BarcodeSetup.barcode();
}

As you can see here, we are getting the two parameters spoken of earlier.  Then we are using that barcodeSetupId parameter to get all the barcodeSetup information.  As you will see later, this will contain our FontSize and FontName.
The next method we want will actually get the text we want and convert it to a barcode.

private BarCodeString barCode()
{
    str barCodeContents = custPackingSlipJour.PackingSlipId;

    if (!barCodeContents)
    {
        return '';
    }

    if (barcodeSetup.validateBarcode(strUpr(barCodeContents)))
    {
        barcode.string(true,strUpr(barCodeContents));
        barcode.encode();
    }
    else
    {
        throw(error(strFmt("@SYS41409", barcode.barcodeType(), strUpr(barCodeContents))));
    }

    if (!barcode)
    {
        return '';
    }

    return barcode.barcodeStr();
}

Here we are checking to see if there is actual text to encode and then using the barcodeSetup to validate that the text we are trying to encode, fits the criteria in the barcodeSetup (such as Maximum/Minimum length). Then we simply return the barcode string.

The rest is pretty easy!  In our ProcessReport method of the DP class, we should call 'this.initBarcode()' and in our setSalesPackingSlipHeaderTmp we should have the following:

if (showBarcode == NoYes::Yes)
{
        salesPackingSlipHeaderTmp.barCode                    = this.barcode();
        salesPackingSlipHeaderTmp.barcodeFontName            = barcodeSetup.fontName;
        salesPackingSlipHeaderTmp.barcodeFontSize            = barcodeSetup.fontSize;
}

This will only add the barcode if the showBarcode box is checked in the parameters.

The only thing left to do is in visual studio.  
Add a new textbox and set it to use the barCode field you added to the HeaderTmp table.
The only tricky part here is using an expression for your FontName and FontSize.

For FontName, simply go in and add the field as an expression.  Very straight forward.
For FontSize, however, you need to do it a little different.  Go into the FontSize and add an expression, except you will need to encapsulate your field in the Cstr() method along with adding + "pt" + at the end.  This will make the 25pt that the report needs.  Here is an example:



That's it.  Not as difficult as I thought it was going to be, however, there were several new concepts that I had to learn.



Re-print a packing slip

The other day I was working on the SalesPackingSlip report and I didn't want to constantly be packing orders to be able to test it.  

If you go to Sales and marketing -> Inquiries -> Journals -> Packing slip you can see all the Packing slip journals and simply Re-print them!

I actually added a barcode to this report and will be explaining that in my next post later today.

Wednesday, March 12, 2014

Images only print on first Cheque

I received an e-mail from a customer on the Cheque_US report that I had modified.  For some reason, it was printing the CompanyLogo and Signatures on the first check but not the subsequent checks.

To print multiple checks you can go to Accounts Payable -> Journals -> Payments -> Payment journal -> Lines. Make sure your journal has multiple lines and you can use Functions -> Generate payments.

In looking at the code, I found that the ChequeDP class was causing the issue.  
*Note:  Whenever I have strange issues with reports, I always check the DP (DataProvider) class first to see if I can find out what is going on.

Anyway, continuing on... IN the ChequeDP class we find a method 'addImagesToFirstRow' that will add the images to your Tmp table.  The problem here is that in the 'insertChequePrintout' method (Line 74), it checks to see if this has already been done.  If it has, it won't do it again.  Hence the dilemma of only printing CompanyLogo/Sigs on the first check.

This is standard AX functionality and I believe it has to do with voided checks... You print the first check and then subsequent checks are voided so you don't want the logo / sigs on it?  I'm not 100% sure on the reasoning for this, however, if I do find a concrete answer I will update this post.

Monday, March 10, 2014

Phantom extra line on SSRS Report

I was working on the SalesInvoice report the other day.  I added a line to the SalesLine section that would display 'Notes' that have been attached to the Sales Line.  All the sales lines would print their note just fine except for the last one and I couldn't figure out why that would be.
Instead of wasting as lot of time and potentially not figuring out the 'why', I decided to simply set the Row Visibility property on the tablix row.

Simply right-click the row and select Row Visibilty.


The next screen is where you will set your expression!

Just make sure that the expression you use is a boolean expression and you are good to go!

Tuesday, February 11, 2014

Unit Conversions

Another project I worked on recently involved Unit Conversions ('Eaches' to 'Lbs'). This one was a tricky one because I wasn't sure how each unit would convert to another unit!  There could be a lot of potential conversions that would have to be made.

Fortunately AX can handle of that for us.  On the Unit conversion form:

 
The User will set up the conversions via this Form and that will determine which conversions can be made and how they are made.

When writing your modifications you can use the UnitOfMeasureConverter class that has methods of CanBeConverted and Convert.  Before converting the unit, simply check if it can be converted!

'modifiedField' on the Table or the Form?

I came across a scenario the other day where my project lead wanted certain things to happen upon a field being modified.  He also stipulated that the changes should take place on the Table if at all possible.

In doing a little research I found that if you are modifying a sys form, as I was (SalesTable), then you should avoid making changes like this to the form itself.  In this case, I was actually able to use the SalesTableType class and modify the 'modifiedField' method.  In this method you will find a switch statement:

Simply add the field you want to have things happen upon 'modifiedField' occuring.

Not all objects have a class like this.  In those cases it would be prudent to check the table of the field that you are dealing with.  You can use the 'modifiedField' method there to make things happen.

Tuesday, February 4, 2014

Label file checkout causes AX Client crash

Not sure why this occurs, but sometimes when you try and checkout a Label file via the Label editor, it will cause the AX client to crash.

The simplest solution I have found for this is going to Version Control -> Synchronization log and then Clean the log.  That should allow you to check it out!

Monday, January 27, 2014

Editing a Cheque SSRS report

Changing Cheque_US design

I recently worked on a project where I had to change the design of the standard US check.

Changing the design was relatively simple.  Run Visual Studio, find the Cheque_US in the SSRS Reports group, right click it and hit edit.  I was able to make all of my changes fairly easily.

The problem that I ran into was that if I wanted to see my changes I had to deploy the report, go to a Payment Journal, add a line in that payment journal and then finally generate a payment.  That was a lot of work to simply see how my changes affected the design.

A friend of mine helped me find a much simpler solution.  Go to Cash and bank management -> Common -> Bank Accounts and select the Set up tab.  In the Layout section, select Check and you will see the Check layout form.



There is a button at the top called 'Print Test' which will allow you to quickly see any changes you have made.  Just be sure to change the 'Check form' option to the U.S. format.

Wednesday, January 15, 2014

Form Datasource Active Record

If you have a form with DataSource MyDatasource, you can access the 'current' or active record in that datasource by simply typing MyDatasource.  .  You can then access all the fields in that record.  This came in very handy in a project I was working on.  

Tuesday, January 14, 2014

Book Recommendation

Microsoft Dynamics AX 2012 Cookbook












This is a GREAT book for beginners.  Step by step instructions along with with excellent "recipes" on how everything works.  The "recipe" is really what makes the difference for me.  A lot of books don't bother to explain each step.

 

Monday, January 13, 2014

What is a table buffer?

This probably seems like a very simple topic, however, that is what we are about here!  I was thinking about this yesterday and wondered what a table buffer REALLY is!  

CustTable custTable;

Declaring a table buffer is relatively simple and straightforward.  We can also populate that table buffer with all the records in CustTable by doing the following:

select custTable;

We now have all the CustTable records in our custTable buffer.  It is important to note that until you perform this step, custTable has NOTHING in it.  You must select records into the buffer to be able to work with them.  
Once selected, you could have more than 1 record, however, only 1 of the records will be the 'active' record in the buffer.  That means when you go to retrieve and/or set information in the record, it will be from the 'active' record.

activeRecordAccount = custTable.AccountNum;
custTable.Account = 123456;

It's important to make sure you have working with the record you want before you change it.

In summary, what is a table buffer?  I'm not sure I have an exact definition of what it is, however, a co-worker gave me the following definition:

"A class that points to a selection of records with up to one 'active' record at a time."

I think this summarizes it pretty well!  Feel free to comment or criticize!






Welcome!

Introduction:

My name is Brad and I have been programming for about 4 years.  I started working with Dynamics AX a little over 6 months ago.

I have decided to start this blog based on the lack of information out there for beginners in this industry.  I hope to be able to pass along some of my experiences, tips, tricks, and any other useful information. Hopefully this can help those who find themselves in the same position as I found myself not too long ago!