Thursday, January 23, 2014

Inventory transaction "Reason Code" field in GP 2013

By Steve Endow

I admit, I am not enough of a Dynamics GP geek to thoroughly review all of the new features and enhancements that come out with each new version (okay, that can actually mean that I'm lazy).   I typically glance at the GP team's features of the day blog posts, but that's about it.

Normally this doesn't pose much of an issue, but the other day I needed to solve a problem, and I was at a disadvantage since I didn't know about a new enhancement in GP 2013 that will meet the requirements quite nicely.

The issue was that a customer was importing inventory adjustments from another system to maintain inventory quantities in Dynamics GP.  When a receipt is submitted to their operational system, an inventory transaction is integrated into GP.  There is a lot of background to the story, but I'll skip the gory details.

This integration works great, and the inventory transactions work fine for the client, but they wanted a way to differentiate these imported inventory transactions from any other inventory adjustment that they enter manually into GP.  I thought that would be tough, since there is no description field on the Item Transaction Entry window or lines.  Fortunately, I called in my colleague Gina and ran the idea by her, and she asked somewhat quizzically, "Why don't you just use the new Reason Code field?".  Uh, ya, sure, that's what I was thinking...

The majority of my customers still use GP 2010 (or GP 10!), so I actually haven't spent as much time with GP 2013 as I should, and I honestly probably hadn't even opened the GP 2013 Item Transaction Entry window until this week.  And there it is, the new Reason Code field that allows you to specify different reasons for each line item on an inventory transaction.


The Reason Codes must be pre-defined, which is a good thing.  Each reason code can have a description, and you can control which transaction types the reason code can be used with.  So some reason codes can be used for Adjustment and Variance transactions, while others might only be used for different types of transfers.


But I found one issue.  As far as I can tell, the new Reason Code field is not available in the Inventory Transaction SmartList.  So my client that wants to see a list of their transactions and differentiate between imported transactions and manually entered transactions will have to build a custom SmartList.  Fortunately they own SmartList Builder, but for customers who don't own SLB, you'll have to come up with some type of workaround.  

Anyway, I thought I would share that little nugget of wisdom in case there is somebody else out there who hasn't scoured the GP 2013 new features list...

Additional Note:  I forgot to check the eConnect 2013 documentation for the new field.  Fortunately, the Reason Code field is available for the taIVTransactionLineInsert and taIVTransferLineInsert, so that is good news.

Steve Endow is a Dynamics GP Certified Trainer and Dynamics GP Certified IT Professional in Los Angeles.  He is also the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter



Friday, November 15, 2013

Unable To Open Select Human Resources Windows?

I ran across an odd case when I was on site with a client a couple of weeks ago.  The users could navigate easily to all of the Human Resources window.  But when they navigated to Employee Maintenance window, clicked Human Resources, and the tried to click Contact....nothing happened.  Nothing.


After doing some troubleshooting, we found that this issue only occurred when users had access to the Project Accounting alternate form for Employee Maintenance.  If we granted access to the standard Microsoft Dynamics GP Employee Maintenance window instead, we did not have the problem (Administration Page-Setup-System-Alternate/Modified Forms and Reports ID).

The good news in all of this is that the bug is apparently resolved in GP 2010 Service Pack 4 which was recently released.

Christina Phillips is a Microsoft Certified Trainer and Dynamics GP Certified Professional. She is a supervising consultant with BKD Technologies, providing training, support, and project management services to new and existing Microsoft Dynamics customers. This blog represents her views only, not those of her employer.

Thursday, October 24, 2013

When good backups just aren't enough

By Steve Endow

Today I was hoping to start a new development project.  I blocked out my day to focus on the project and was ready to dig into some code.

This morning I fired up one of my HyperV virtual servers that was setup for this particular type of development and opened Google Chrome to login to a web site for the project.  Chrome was setup to load Google.com by default, but when the browser opened, the page didn't display--it said something about "unable to establish ssl connection".  Hmmm.  I then tried a few other web sites.  Some would partially load, some would display text but no images, some would display scrambled images, and some wouldn't load at all.

I thought maybe it was a network issue--since I moved recently, all of my servers detected my new network and required me to select the network type before the network started working properly.  But even after checking the network settings, pages still wouldn't load.  I then tried Internet Explorer and Firefox, but both of those browsers exhibited the same strange symptoms.  So it seems the problem was with the machine, and was not a browser issue.

I then tried to install an application on the machine, but the setup.exe would immediately crash.  Hmmm.

I thought maybe there is a small chance that some type of virus or malware got onto the server, although that seems highly unlikely for this particular VM.  So I tried to install my anti-virus--but I couldn't install that either--the setup just crashed immediately no matter what I tried.  I tried several other things, but none of them worked.  This virtual machine that worked fine just a few months ago was now unusable.

So I then pulled up a backup.  Oh, did I mention I'm a big fan of backups?


In addition to the above backups for my workstation files, I have scripts that backup all of my HyperV virtual servers every week.  A copy of each VHD is saved to my file server, then the VHDs are compressed using 7-Zip.  A copy of the 7-Zip archives are then saved to an external drive.  And I have two external drives that I rotate each week to a fire safe.

So on my file server I grabbed the VHD backup from 10/11/2013.  I restored the VHD and restarted the VM.  But the same problems existed.

I then went back two weeks, and restored an older VHD, but it had the same issues.  I was then able to resurrect a backup from 9/14, nearly SIX WEEKS old, but alas, even that had the issue.

So this was an interesting case where despite my very comprehensive backup system that worked great and allowed me to easily restore a copy of a 64GB VHD from six weeks ago, it apparently was not old enough.

You might think that this is a rare exception, but based on my experience, it's actually fairly common.  I've had clients discover that they have a problem that is several months old.  Or they discover that something was deleted or changed or overwritten months ago.  In those cases, their 4 week backup rotation doesn't help them.  They would have needed monthly archives saved for 6 or more months.  In my experience, these types of "quiet" problems have been much more common than any dramatic disaster, drive failure, or server meltdown.  Many backup strategies focus on restoring a recent copy of a file, but fail to consider the possible need to restore an older copy of a file.  It's a more difficult backup strategy, requires more management, and requires more storage space.

But it can be valuable in situations like what I experienced today.


Steve Endow is a Dynamics GP Certified Trainer and Dynamics GP Certified IT Professional in Los Angeles.  He is also the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter


Tuesday, October 15, 2013

Year Over Year Comparison in SQL

Either we are slacking, or we are both so busy lately! We had a great time at Technical Airlift, and I am gearing up for the Partner Event (GPCC) and GPUG Summit next week in lovely Tampa, FL.  In the meantime, here is a little bit I put together based on a Victoria Yudin script to pull an account balance as the back end to a dashboard to display year over year balances by GL account.  So this crosses both open and history years...

--CTE to pull current year account balances by year
With CTECurrentYear (Account, AcctDesc, Balance, GLYear) as
(select a.actnumst Account, m.actdescr AcctDesc, ISNULL((sum(g.DEBITAMT-g.CRDTAMNT)),0) Balance, g.OPENYEAR GLYear
from GL20000 g
inner join GL00105 a
on a.ACTINDX = g.ACTINDX
inner join GL00100 m
on g.ACTINDX=m.ACTINDX
where a.ACTNUMST IN ('list out the GL accounts here') group by a.actnumst, m.actdescr, g.openyear),

--CTE to pull historical year account balances by year
CTEHistoryYear (Account, AcctDesc, Balance, GLYear) as
(select a.actnumst Account, m.actdescr AcctDesc, ISNULL((sum(g.DEBITAMT-g.CRDTAMNT)),0) Balance, g.HSTYEAR GLYear
from GL30000 g
inner join GL00105 a
on a.ACTINDX = g.ACTINDX
inner join GL00100 m
on g.ACTINDX=m.ACTINDX
where a.ACTNUMST IN ('list out the GL accounts here') group by a.actnumst, m.actdescr, g.HSTYEAR)

--Select statement to union both together
Select account, acctdesc, balance, GLyear from CTECurrentYear
union all
select account, acctdesc, balance, GLyear from CTEHistoryYear
order by account, GLYear

Hope to see you in Tampa!

Thursday, September 26, 2013

Dynamics GP SQL Server Composite Primary Key Trivia

By Steve Endow

Coincidentally, after working on a really interesting Dynamics GP SQL Server performance issue earlier this week, I will be having a call tomorrow with another GP partner and GP customer to discuss a different Dynamics GP SQL performance issue.

This time, it involves an eCommerce web site that is trying to stay synchronized with Dynamics GP.  I don't have much information on the integration at the moment, but I do have a list of requests from the web developers.  They are asking that several indexes be added to Dynamics GP.

When I reviewed their request for new indexes, I looked at the GP tables to see what indexes already existed on the tables.

One example is that they requested an index for CUSTNMBR on the SOP10107 table.  The SOP10107 table has a composite primary key (a key consisting of multiple fields), but does not have any additional indexes (at least not on my GP 2010 TWO database).

So the developers are apparently asking for an index on CUSTNMBR, the first field in SOP10107.

But CUSTNMBR is one of the fields in the primary key.  Doesn't SQL Server use the primary as an index?  I didn't actually know and had to do some research.

The answer is one of my favorites:  It depends.

Apparently, if you query the first field in a composite primary key, or all fields in the composite primary key, the primary key can be used as an index.  But if you query the second or subsequent fields in the key, then the primary key cannot be used as an index.

I need to track down the MSDN or TechNet documentation to back this up, but I initially found it explained in two threads on StackOverflow:

http://stackoverflow.com/questions/4381921/composite-primary-key-and-additional-indexes

http://stackoverflow.com/questions/3613103/indexing-individual-fields-of-sql-server-composite-keys


I haven't researched the specific mechanics of the primary key in SQL Server to understand exactly why this limitation exists, but I have speculated about the reason and can understand why it might be the case.

So there you go.  Now you can talk fancy about SQL Server composite primary keys at your next social gathering!  You will be the life of the party.

Steve Endow is a Dynamics GP Certified Trainer and Dynamics GP Certified IT Professional in Los Angeles.  He is also the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter


Wednesday, September 25, 2013

A most EPIC tale of troubleshooting a Dynamics GP SQL performance issue

By Steve Endow

Today was a very good day.  After hours of effort by a team of three consultants, we solved a vexing Dynamics GP SQL performance issue for a client.

I'll start with the conclusion and explain why this was such a great achievement.

1. We actually identified the cause of the performance problem.  For those that have tried to identify the cause of GP running slowly, locking up, or not responding, you know how difficult this can be.  Working together, our team of 3 was able to conclusively track down the specific SQL stored procedure that was causing the problem.  This was quite an accomplishment.

2. It took the combined effort of three consultants with three different areas of expertise and a lot of combined Dynamics GP, networking, and SQL Server experience to identify the cause.  In my experience, it is very, very, rare to have the opportunity to assemble such a team to work on this type of issue, and it was a great experience for all of us.

3. The client was willing to invest in consultants and made the commitment to identify and resolve the issue.  So often I've had situations where a client was plagued with performance issues, but there wan't a strong commitment to resolve them.  The client will likely spend several thousand dollars resolving this particular issue, but I believe it was a worthwhile investment--or I will once we finally resolve the issue.

And with that, some background...

The Dynamics GP 2010 client contacted their partner in the San Francisco Bay Area a few months ago complaining about performance problems with Dynamics GP.  GP is sporadically slow, and sometimes hangs or stops responding completely.  The "lock up" can last from 5 minutes to 20 minutes and affects multiple users at different times.

The GP partner looks into it, but because the issue is so unpredictable and can't be reproduced on demand, no cause is identified in Dynamics GP or SQL.  Apparently the problem continues and gets even worse.  At this point, the client requests a network expert to try and determine if a network issue is causing the problem.  The GP partner identifies a networking data communications consultant in Denver and flies him out to San Francisco this week.

After two days of network traffic monitoring and traces, the network consultant, working with the GP consultant, is able to capture the actual network packets that are occurring in the seconds leading up to the performance issues in Dynamics GP.  Like a countdown, he is able to list the users, the actions they were performing in different applications, and the data in the network packets that were being issued by those users at the exact time that the problem occurred.

This data indicated that a revenue recognition application used by the client was issuing queries against the Dynamics GP database.  He assembled the contents of the network packets, and saw that the "rev rec" application was querying the Extender "EXT" tables in Dynamics GP.  When implementing Dynamics GP and the revenue recognition system, the client chose to store additional sales order invoice field values in Extender windows that could be used to perform rev rec calculations.  So this all makes sense.

Since the network consultant had uncovered a pile of SQL, the Dynamics GP consultant called me to decipher the SQL activity and determine how it might relate to the performance issue.  Coincidentally, my blog-mate Christina Phillips and I just presented last week at the Tech Airlift 2013 conference in Fargo, and the topic of our presentation was "SQL Skills for Consultants".  While I am by no means a super-SQL-guru, I regularly get calls like this to solve some tricky problems, so I have had a fair amount of experience in this area.

So today I had a few GoToMeeting sessions with the GP consultant and network consultant where we pored over the SQL activity and dug into the Dynamics GP company database to understand what was going on.

We saw that the rev rec application issued a select statement against the EXT00100 table, and then called a custom stored procedure.  Immediately after that stored procedure is called, Dynamics GP locks up for one user.  A few seconds later, GP locks up for another user, and then another.  So the network consultant had identified our culprit:  a custom stored procedure.

After reviewing the network trace data, the GP consultant knew the specific actions that were being performed in the rev rec system and in Dynamics GP, so she was able to get the users to reproduce the issue.  Suspecting that we had a locking issue on our hands, I sent her a slightly modified version of the "dynamic management view" query from this Stack Overflow thread that identifies blocked and blocking processes in SQL Server.


SELECT
t1.resource_type,
t1.resource_database_id,
t1.resource_associated_entity_id,
t1.request_mode,
t1.request_session_id,
s1.login_name, 
s1.program_name, 
s1.host_name, 
s1.nt_user_name, 
t2.blocking_session_id,
o1.name 'object name',
o1.type_desc 'object descr',
p1.partition_id 'partition id',
p1.rows 'partition/page rows',
a1.type_desc 'index descr',
a1.container_id 'index/page container_id'
FROM sys.dm_tran_locks as t1
LEFT OUTER JOIN sys.dm_os_waiting_tasks as t2
      ON t1.lock_owner_address = t2.resource_address
LEFT OUTER JOIN sys.objects o1 on o1.object_id = t1.resource_associated_entity_id
LEFT OUTER JOIN sys.partitions p1 on p1.hobt_id = t1.resource_associated_entity_id
LEFT OUTER JOIN sys.allocation_units a1 on a1.allocation_unit_id = t1.resource_associated_entity_id
LEFT OUTER JOIN sys.dm_exec_sessions s1 ON s1.session_id = t1.request_session_id
WHERE o1.name IS NOT NULL



When she sent me the results of the query, it painted a great picture of the problem.  Here is a screen shot of the query results--I know it looks busy, but stay with me, it's pretty simple to interpret.


Notice that the highlighted row is the only one with a value in the "blocking" column.  That means that an application is trying to perform an operation on the EXT00100 table, but is being blocked by another process.  Notice that the "request_mode" column on that row says "IX".  This means that the row in yellow is waiting for an "exclusive" lock on the table, in this case because it is trying to update the EXT00100 table.

When a SQL process is blocked, it typically causes the calling application to wait--it will often just sit there and be completely unresponsive as it waits for the SQL command to finish.  The SQL operation usually finishes in a fraction of a second, but if the process is blocked, it may wait for a minute, or perhaps indefinitely, until the operation completes.

The Dynamics GP consultant knew that particular yellow row was a Dynamics GP user--the user reported that GP was locked up.  So this told us that something was locking the EXT00100 table, and that is why Dynamics GP was locking up--it was waiting indefinitely for the table to become available for an update.

Which leads us to the records for process 178.  178 is the process that is blocking the update to EXT00100.  But why is it blocking?  Well, if you look at the "request_mode" values, most have a value of "S", which means "shared lock".  Shared locks allow other processes to read the locked data, but the data cannot be changed or updated while the shared lock is present.  So process 178 appears to have issued SELECT queries against the EXT tables, with the default shared lock, that are preventing Dynamics GP from updating those tables.

Fundamentally, this isn't a problem--a query can retrieve data from the EXT tables, complete in a fraction of a second, and then the shared lock is released.  But for some reason, the shared lock of process 178 persisted for up to 20 minutes at a time.  During that time, Dynamics GP would become unresponsive if a user tried to update any Extender records.

So, now that we know why GP is locking up, the next question is: Why is a mysterious query against the EXT tables locking them for 20 minutes?  For that, we go back to the network packet trace, and find packet 33823 documented by the network consultant:

Packet 33823 – hq-app1 issues a SQL command to run a Stored Procedure on the SQL Server 

Exec CORP..spREVREC_EXTENDER 'CORP\username', '2013-09-24 03:35:30:35', 'EXT_REVREC'


Aha, now we are getting to the root of the problem.  There is a custom stored procedure called "spREVREC_EXTENDER" that is being called--this procedure is what is locking the tables under process 178.  We deduce that this custom stored procedure was developed by the revenue recognition software vendor to extract data from Dynamics GP for analysis.

When then jump back to SQL Server Management Studio and pull up that custom stored procedure so that we can view its contents.  Except...it is encrypted.  D'oh!

Never fear, as I have a tool that can decrypt stored procedures with a single click.  After some file transfer acrobatics, we finally get a copy of the customer database onto my development machine so that I can use the decryption tool.  And voilà, we can now see the contents of the stored procedure.  And it is a doozie.  It is 160 lines with 2 derived tables and 12 joins.  (Attendees of our SQL Skills for Consultants presentation at the Tech Airlift would know that a good substitute for a derived table is a CTE, and that CTEs can be helpful in improving query performance!)

So now it is crystal clear what is happening.  The stored procedure, with its 2 derived tables and 12 joins, is taking forever to run.  It was developed against a brand new Dynamics GP company database that only had a few records--of course it ran fine back then.  Now that the customer has 100,000 records in the SOP tables and each of the Extender tables, it takes anywhere from 5 to 20 minutes to run.  It's a classic example of how it is often impossible to predict future performance of a complex query, and why SQL query optimization is important.

But that's not all.  It isn't just that it has 12 joins--it's the particular table that it is joining and the fields it is using in the join.  This is just a small snippet of the query--to anyone familiar with Extender tables, it should be fairly obvious that this isn't going to end well.


from EXT00100 e
INNER JOIN EXT00102 d1 ON d1.PT_Window_ID = e.PT_Window_ID and d1.PT_UD_Key = e.PT_UD_Key and d1.PT_UD_Number = 1 
INNER JOIN EXT00102 d2 ON d2.PT_Window_ID = e.PT_Window_ID and d2.PT_UD_Key = e.PT_UD_Key and d2.PT_UD_Number = 2
INNER JOIN EXT00103 t1 ON t1.PT_Window_ID = e.PT_Window_ID and t1.PT_UD_Key = e.PT_UD_Key and t1.PT_UD_Number = 3
INNER JOIN EXT00101 s1 ON s1.PT_Window_ID = e.PT_Window_ID and s1.PT_UD_Key = e.PT_UD_Key and s1.PT_UD_Number = 6
INNER JOIN EXT00101 s2 ON s2.PT_Window_ID = e.PT_Window_ID and s2.PT_UD_Key = e.PT_UD_Key and s2.PT_UD_Number = 7
INNER JOIN EXT00103 t2 ON t2.PT_Window_ID = e.PT_Window_ID and t2.PT_UD_Key = e.PT_UD_Key and t2.PT_UD_Number = 4
INNER JOIN EXT40102 m 
ON m.PT_Window_ID = t2.PT_Window_ID 
and m.Field_Number = t2.PT_UD_Number 
and m.LNITMSEQ = t2.TOTAL
INNER JOIN EXT00103 t3 ON t1.PT_Window_ID = e.PT_Window_ID and t3.PT_UD_Key = e.PT_UD_Key and t3.PT_UD_Number = 5
INNER JOIN SOP30200 h 
ON h.SOPNUMBE = rtrim(e.Key_Strings_2) 
-- and h.SOPTYPE = convert(INT,e.Key_Strings_3)-1
INNER JOIN REV_REC_MASTER a
ON a.SOPNUMBE = h.SOPNUMBE 
AND a.ORIG_SOPTYPE = h.SOPTYPE
AND a.LNITMSEQ = convert(INT,e.Key_Strings_1)
AND a.VOID_FL = 0
INNER JOIN REV_REC_RULES b
ON b.SOPNUMBE = h.SOPNUMBE 
AND b.ORIG_SOPTYPE = h.SOPTYPE
and b.LNITMSEQ = convert(INT,e.Key_Strings_1)
and b.DELETE_FL = 0
and b.VOID_FL = 0
LEFT OUTER JOIN REV_REC_TRX_RULES r
ON r.SOPNUMBE = a.SOPNUMBE and r.LNITMSEQ = a.LNITMSEQ


I haven't yet dug into the query to determine the specific causes of the performance issues, but one leading candidate is the join with "rtrim(e.Key_Strings_2)".  That is a join using a function on a non-indexed field.  I sense trouble ahead.

At this point, we have identified the cause of the GP lockups and know that we need to have the rev rec vendor modify the custom stored procedure.

I'm guessing that a quick fix would be to simply add the "WITH (NOLOCK)" table hint to the query.  In theory, this should eliminate the shared lock and allow GP to update the EXT tables without issue.  But that would just be covering up the underlying problem--the stored procedure would still take 5 to 20 minutes to run.  And using NOLOCK on a query that runs that long is probably a bad idea.

So we will likely need to work with the rev rec vendor to completely restructure the query so that it runs much faster.  Preferably in just a few seconds.

Despite the work ahead, we felt pretty good by 5pm today, as we were confident that we had found the cause of the client's performance issue, and knew that it could be fixed.

It was a good day.


Postscript:  Some of you may know that with GP 2013, eOne completely redesigned the table structures for Extender.  The tables have different names, and work differently than the prior Extender tables.  So, when this client upgrades to GP 2013, the revenue recognition stored procedure will have to be redesigned yet again to query data from the new 2013 Extender tables.


For more information on different types of SQL locks, here is a good TechNet article on SQL locking:

http://technet.microsoft.com/en-us/library/aa213039(v=sql.80).aspx


Steve Endow is a Dynamics GP Certified Trainer and Dynamics GP Certified IT Professional in Los Angeles.  He is also the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter


How NOT to develop an eConnect integration: Lesson #29

By Steve Endow

I've come across some really bad Dynamics GP integrations.  I had one where the developer made a really pretty user interface with their own company logo and fancy controls and dynamic layout, but the import simply didn't work and the developer didn't know the difference between a debit and credit.

Then I saw another one where the developer wrote their own massive stored procedures to import GL and AP transactions into GP tables (I'm hoping that was done before eConnect existed).  Scary stuff.

I got a call last week about an old integration that stopped working when a customer tried to set it up on a new Windows 7 x64 machine.  The integration fails with two errors.  The first appears to indicate that it encountered an error when it tried to read the source data file.  And the second error says that the Crystal Reports runtime is not installed correctly.

Say what?

I got a copy of the .NET executable and decompiled it to try and find some clues.  I found the section of code that is failing when reading the data file, but it isn't obvious why it is failing--the developer didn't bother to output any error messages in their error handling code, just a useless "There were errors loading data" message.

So then I move on and look for the Crystal Reports reference.  Sure enough, the application relies on Crystal Reports version 10.2.3600.  For those of you with long memories, Crystal Reports 10 is from around 2004.  I have a copy of it, but my version isn't 10.2.3600, so I'm guessing it won't help.  So now we're stuck digging around an old machine to try and find the right Crystal DLLs and see if we can get the import working again, and worrying that there may be some compatibility issue with Windows.

So why does a GP integration use Crystal Reports?  Apparently the developer thought it would be super cool if he used Crystal Reports to display errors.  No joke.  So if the import has an error, the application launches a Crystal Reports runtime window to display the errors...in a Crystal Report.

So in a nice paradox, the application is encountering an error, and it then tries to display the Crystal Report to present the error, but Crystal Reports isn't working, so we get another error, and we are unable to see what the first error is.

They could have gone with a dialog box. They could have used a text box.  They could have written to a text log file.  They could have sent an email.  All of those options would have been much simpler, easier, and worked just fine.  But no, they had to get all fancy and bill the client a few more hours to build a Crystal Report just to display errors.  Face palm.  And now that 2004 version of Crystal Reports is ancient and is preventing the app from working on a newer version of Windows.

If you are developing an eConnect integration, or any simple business application for that matter, please just keep it simple.  There is no need to Bedazzle a basic application like a data import.  And when the application lasts for years and years and needs to be upgraded as the client upgrades GP, the simple application will be easier to upgrade, maintain, and support.

The developer who wrote this integration with Crystal Reports did not impress anyone, yet left a legacy of hassle and frustration due to a poor design choice.


Steve Endow is a Dynamics GP Certified Trainer and Dynamics GP Certified IT Professional in Los Angeles.  He is also the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter