Hi all,
I am making a custom screen for Sales order. Everything was fine when I am making a sales order from 1 PC. However, when 2 users from 2 different PCs is making a sales order and posting the sales orders at the same time, this error occurs. It occurs while adding item line (SOPOrderReturnLine) for the sale order.
Sage.ObjectStore.DeadlockException: Transaction (Process ID 59) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. at Sage.Common.Exceptions.ExceptionManager.Throw(Exception e) at Sage.ObjectStore.DataSourceExecutor.<>c__DisplayClass4.<RunLocal>b__0() at Sage.ObjectStore.TransactionContext.RunAction(Action action) at Sage.ObjectStore.DataSourceExecutor.RunLocal() at Sage.ObjectStore.DataSourceExecutor.Run() at Sage.ObjectStore.DataSourceAccessor.DataSourceCollectionEnumerator.Run() at Sage.ObjectStore.DataSourceAccessor.DataSourceCollectionEnumerator.System.Collections.IEnumerator.Reset() at Sage.ObjectStore.DataSourceAccessor.GetEnumerator() at Sage.ObjectStore.PersistentObjectCollection.Fill() at Sage.ObjectStore.PersistentObjectCollection.FillInternal() at Sage.ObjectStore.PersistentObjectCollection.get_Count() at Sage.ObjectStore.PersistentObjectCollection.AddNew() at Sage.Accounting.SOP.SOPStandardItemLine.CreateOrderAllocationLine(AllocationBalance oAllocationBalance) at Sage.Accounting.SOP.SOPStandardItemLine.OnStockAllocation(AllocationBalance oAllocationBalance, Decimal QuantityNotAllocated, Boolean AllocationFailure) at Sage.Accounting.Stock.StockPosting.OnStockAllocation(AllocationBalance oAllocationBalance, Decimal QuantityNotAllocated, Boolean AllocationFailure) at Sage.Accounting.Stock.StockWarehouseAllocationPosting.UpdateInternal() at Sage.Accounting.Stock.StockPosting.Update() at Sage.Accounting.Stock.StockWarehouseAllocationActivity.UpdateBinItem(BinItem oBinItem, Decimal dfQuantityToAllocate, Decimal dfQuantityToReserve, Boolean bAllowNegativeStock, Boolean bCreatePreReceipts) at Sage.Accounting.Stock.StockWarehouseAllocationActivity.ReserveStock() at Sage.Accounting.Stock.StockAllocationActivity.SetQuantityProtected(Decimal value) at Sage.Accounting.Stock.StockAllocationActivity.UpdateInternal() at Sage.Accounting.Stock.StockActivity.UpdateWorker(Boolean inServiceCall) at Sage.Accounting.Stock.StockActivity.Update() at Sage.Accounting.SOP.SOPStandardItemLine.CreateAllocationActivity(BinItem oBin, Decimal dAllocateQuantity, TraceableSOPAllocationAdjustment oTraceableAdjustment) at Sage.Accounting.SOP.SOPStandardItemLine.AdjustAllocationLines(Decimal dQuantityAdjustment, BinItem oBinItem, Boolean bAllocateIndividualItems, TraceableSOPAllocationAdjustment oTraceableAdjustment) at Sage.Accounting.SOP.SOPStandardItemLine.AdjustAllocationLines(Decimal dQuantityAdjustment, BinItem oBinItem) at Sage.Accounting.SOP.SOPStandardItemLine.PostProtected(Boolean CreateCancelledLine) at Sage.Accounting.SOP.SOPOrderReturnLine.Post(Boolean CreateCancelledLine) at Infusion.Fastafood.Sage2002011.Business.SOPOrderLayer.AddNonTraceableStandardItemLine(SOPOrderReturnLine Line)
In the process, this is what I did.
1. create order
2. lock order
3. create item line "SOPOrderReturnLine" < The error occurs here
4. add charge line, discount like if any
5. complete order, unlock order
6. immediately make deliveries and invoices.
The making of order:
public void CreateOrder(SYS.SOPOrderType SOPOrderType, long formid) { bool applyBestDiscount = false; bool overrideOnHold = true; bool confirmLines = true; bool successful = false; orderType = SOPOrderType; Sage.Accounting.Common.ActiveLock activeLock = null; try { //int unprintedInvoiceCount = GetUnprintedInvoiceCount(); Sage.Accounting.SalesLedger.SalesCreditNoteInvoiceNumber salesCreditNoteInvoiceNumber = Sage.Accounting.SalesLedger.SalesCreditNoteInvoiceNumberFactory.Factory.Fetch(); //Set the order number if (!this.sopLedger.Setting.AutoGenOrderReturnNos) { long nextInvoiceNo = salesCreditNoteInvoiceNumber.NextInvoiceNumber; long currentInvoiceNo = 0; order.DocumentNo = (salesCreditNoteInvoiceNumber.NextInvoiceNumber).ToString(); SharedLayer sharedLayer = new SharedLayer(); do { currentInvoiceNo = nextInvoiceNo; this.order.DocumentNo = nextInvoiceNo.ToString(); int numberOfZero = 10 - this.order.DocumentNo.Length; while (numberOfZero != 0) { this.order.DocumentNo = "0" + this.order.DocumentNo; numberOfZero--; } nextInvoiceNo++; } while (sharedLayer.isDocumentNoExist(this.order.DocumentNo)); order.Fields.FindItem("InvoiceNumber").Value = currentInvoiceNo; salesCreditNoteInvoiceNumber.NextInvoiceNumber = currentInvoiceNo + 1; salesCreditNoteInvoiceNumber.Update(); salesCreditNoteInvoiceNumber.Dispose(); salesCreditNoteInvoiceNumber = null; } // Set the order to be full order entry (as opposed to trade and rapid) order.EntryType = Sage.Accounting.SOP.SOPOrderEntryTypeEnum.EnumSOPOrderEntryTypeFull; //Warehouse Sage.Accounting.Stock.Warehouses warehouses = new Sage.Accounting.Stock.Warehouses(); order.Warehouse = warehouses.First; //SOP Order Type switch (orderType) { case SYS.SOPOrderType.Normal: order.Fields.FindItem("SOPOrderType").Value = "Normal"; break; case SYS.SOPOrderType.Mixed: order.Fields.FindItem("SOPOrderType").Value = "Mixed"; break; case SYS.SOPOrderType.Prepaid: order.Fields.FindItem("SOPOrderType").Value = "Prepaid"; break; case SYS.SOPOrderType.Reserved: order.Fields.FindItem("SOPOrderType").Value = "Reserved"; break; } order.DocumentCreatedBy = Sage.Accounting.Application.ActiveUserName.ToString(); // Save the order before we add lines order.Update(); // Lock the order so that no one else can amend it activeLock = Sage.Accounting.Application.Lock(order); originalSequence = new List<short>(); //Standard LIne if (this.order.Lines.Count > 0) { foreach (SOPOrderReturnLine line in order.Lines) { line.Fields.FindItem("XCustomerID").Value = order.Customer.SLCustomerAccount; Sage.Accounting.Stock.StockItems sis = new Sage.Accounting.Stock.StockItems(); sis.Query.Filters.Add(new Sage.ObjectStore.Filter(Sage.Accounting.Stock.StockItem.FIELD_CODE, line.ItemCode)); sis.Find(); if(sis.First != null) { line.Fields.FindItem("XItemID").Value = sis.First.Item; } AddNonTraceableStandardItemLine(line); } } // Add a standard stock item AddCustomizeLine(); // Add an additional charge for carriage AddAdditionalChargeLine(); // Amend auto discount unit price // Apply order discounts ApplyDiscount(); // Validate the order ConfirmSalesOrder(order, applyBestDiscount, overrideOnHold, confirmLines); Sage.Accounting.Application.AllowableWarnings.Add(order, typeof(Ex20235Exception)); order.Post(applyBestDiscount, overrideOnHold); if (orderType == SYS.SOPOrderType.Normal) { rearrangePrintSequenceNumber(order.SOPOrderReturn, originalSequence); } successful = true; } catch (Sage.Accounting.Exceptions.Ex20579Exception Ex20579Exception) { MessageBox.Show(Ex20579Exception.Message + " Order is cancelled. "); Logger.WriteLog("Ex20579Exception error=" + Ex20579Exception.ToString()); order.Cancel(); }catch (OrderNumberAlreadyExistsException orderNoAlreadyExistsEx) { Logger.WriteLog("DocumentNo="+order.DocumentNo+"; orderNoAlreadyExistsEx="+ orderNoAlreadyExistsEx.ToString()+";"); MessageBox.Show("["+order.DocumentNo + "] " + orderNoAlreadyExistsEx.Message); order.Cancel(); } catch (Exception oException) { MessageBox.Show(oException.Message + " Order is cancelled. ", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Logger.WriteLog("oException error=" + oException.ToString()); order.Cancel(); } finally { // Make sure we unlock the order if (activeLock != null) { activeLock.Dispose(); } if (successful) { Sage200InvoiceTransaction(formid); } } }
AddNonTraceableStandardItemLine() function is called to create new SOPOrderReturnLine for the order. The error is happening during the SOPOrderReturnLine.Post();
private void AddNonTraceableStandardItemLine(SOPOrderReturnLine Line) { //Tax Code Sage.Accounting.TaxModule.TaxCode taxCode = Sage.Accounting.TaxModule.TaxCodeFactory.Factory.FetchTaxCodeWithCode(2); Sage.Accounting.Stock.Views.WarehouseStockItemViews warehouseStockItemViews = new Sage.Accounting.Stock.Views.WarehouseStockItemViews(); SOPStandardItemLine line = Line as SOPStandardItemLine; originalSequence.Add(short.Parse(line.PrintSequenceNumber.ToString())); try { //(1) POPOrder line.SOPOrderReturn = order; //(2) WarehouseItem Sage.Accounting.Stock.Views.WarehouseStockItemView warehouseStockItemView = null; // Add the stock item filter warehouseStockItemViews.Query.Filters.Add(new Sage.ObjectStore.Filter(Sage.Accounting.Stock.Views.WarehouseStockItemView.FIELD_ITEM, line.Item.Item)); warehouseStockItemViews.Query.Filters.Add(new Sage.ObjectStore.Filter(Sage.Accounting.Stock.Views.WarehouseStockItemView.FIELD_USEFORSALESTRADING, true)); warehouseStockItemViews.Query.Sorts.Add(new Sage.ObjectStore.Sort(Sage.Accounting.Stock.Views.WarehouseStockItemView.FIELD_WAREHOUSEID, false)); warehouseStockItemViews.Query.Find(); // Find the first warehouse bin that has available stock foreach (Sage.Accounting.Stock.Views.WarehouseStockItemView view in warehouseStockItemViews) { if (view.FreeStockAvailable > System.Decimal.Zero) { warehouseStockItemView = view; break; } } if (warehouseStockItemView != null) { line.WarehouseItem = warehouseStockItemView.WarehouseItem; line.SellingUnit = line.Item.Units.First; line.LineTaxValue = 0; line.TaxCode = taxCode; line.TaxCodeDbKey = taxCode.SYSTaxRate; line.AnalysisCode1 = order.AnalysisCode1; // Save the line line.Post(sopLedger.Setting.RecordCancelledOrdLines); line.Update(); } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); Logger.WriteLog("AddNonTraceableStandardItemLine - "+ex.ToString()); } }
After I Google the error, it is related to SQL Server where more than 2 processes is waiting for the other to finish transaction. I am suspecting I messed up at stage 2, but locking the order is necessary.
How do I prevent this error?
Thank you.