As you may have figured out from past posts, I like working with Dynamics GP Web Services when building integrations that involve our business systems. That isn’t to say that there aren’t rough spots occasionally. My latest wrestling match with it involved updating Sales Invoices. Since I couldn’t find information on this issue at all, I thought I’d post my struggle and solution for others in the same situation in future to find.
The Setup
We have multiple bins configured on our sales invoices so that we can coordinate our warehouse folks and get orders shipped quickly. That means that for each line on the invoice, inventory can come from one or more bins (if needed) to fulfill the order. Since GP isn’t very flexible in its automatic bin assignment, we have an addin that we run to allocate bins. I programmed the addin.
Sending a sales document through GP Web Services with multiple bins attached to each line item was impossible to do on Sales Orders because of a bug in the update procs that I found a couple months ago (where the bins simply aren’t updated). As a result, we have to wait until an invoice is created for the document to be able to assign bins through the web services. A pain, but not a huge deal, really.
The Specs
Dynamics version: 10.00.1368
SQL Server version: 2005
Visual Studio: 2010 (10.0.30319.1)
Target Framework: .Net Framework 3.5
Transport: WCF using basicHttpBinding
The Problem
The thing is, I was having trouble making my bin allocation re-entrant. It could be that you might want to run bin allocation twice on a batch of invoices if, say, you had shortages in the available bins on one or two orders but were able to move things around a bit to make it work. It seems reasonable. Then, too, we found that another process that was updating shipping dates on invoice batches was causing problems, as well.
A little experimentation showed that updating an invoice through the web services that already had multiple bins allocated caused Dynamics GP to lose track of the allocations entirely. Fortunately, it did so in such a way that the inventory wasn’t messed up—i.e. it reverted back to the bins they had come from. Unfortunately, I could find no way to allow my bin allocations to be re-entrant and/or for my batch date change application to touch my Sales Invoices without bad things happening.
I found that even if you sent an absolutely unaltered invoice back to GP in a web services update operation, it’d lose bin allocations if they existed—whether your update included those bin allocations or not.
The Solution
I finally got a wacky idea that turns out to work a dream. It’s less than ideal, but hey, it works without having to drop down to eConnect or anything even less friendly. The trick is to fake Dynamics out with a superfluous update if you have an order with bins already allocated. Here’s the code:
public List<CustValidationItem> CommitSalesInvoice()
{
OnCommitting();
GPService.SalesInvoice si = originalSalesDocument as GPService.SalesInvoice;
if (si == null)
{
si = new GPService.SalesInvoice();
}
else
{
int allocatedCount = si.Lines.Count(l => l.QuantityFulfilled.Value > 0M);
if (allocatedCount == si.Lines.Count())
{
fakeoutUpdate(si);
}
}
In this code, originalSalesDocument is completely untouched and exactly the invoice as read from the web service earlier. If you were to break after fakeoutUpdate() is called, the invoice would have no bins allocated for any of the line items.
Note that I have a potential bug in there if an invoice is ever partially allocated (because then allocatedCount would be less than the total number of lines), but I’m considering that a feature for now (because it will de-allocate all bin allocations on that invoice and send up red flags throughout our system).
And just to put all the cards on the table, here’s fakeoutUpdate in its entirety:
private void fakeoutUpdate(GPService.SalesInvoice invoice)
{
// If bins are already allocated, the next update deletes the allocation regardless of what is sent.
// This update is to de-allocate the order while preserving the bins we know about already so they'll
// save properly later in the process.
GPManager.Service.UpdateSalesInvoice(invoice, GPManager.GetContext(), UpdateSalesPolicy);
}
There’s another potential bug if you get another user updating the same sales invoice from a different machine between the time the fake is run and the actual update. Fortunately, the total time between the two updates is literally microseconds. Indeed, our order processor says that there is no noticeable difference in the time it takes to commit updates between the new process and the old one. Subjective, I know, but good enough.
The Takeaway
I find it odd that such simple and universal bugs have made it into the release of the product. It speaks poorly of the testing done at Dynamics headquarters. These aren’t bugs that should have been able to slip through a minimally competent QA process. It’s clear that nobody tested updating invoices in a multiple bin scenario. At least, not in a way that checked that the bin allocations survive the update.
I also find the lack of information out there disturbing. It makes me feel like I’m the only developer using Dynamics GP Web Services for anything beyond the most basic functions. I know that can’t be true, but you couldn’t prove it by the amount of chatter on the interwebs. I’ve noticed before that business line developers are under-represented out here and this reinforces that feeling. The only Dynamics blogs I’ve been stumbled across seem to be vendors and/or supply channel/party line outlets. These blogs talk enough about the abomination that is Dexterity, but almost none at all about alternatives like eConnect or GP Web Services.