Hi Stuart,
Thank you so much for helping with this.
Your code snippet provided one piece of enlightenment that I'd not been able to discover through the F12 object explorer in VS2019: how to assign a specific logical warehouse ID.
This code is part of a standalone plugin:
- Code: Select all
class ConfigurationForm : JiwaFinancials.Jiwa.JiwaApplication.Maintenance.UserInterface{ ... }
I initially avoided including code, because it seemed such a big segment. This is the method that is failing:
- Code: Select all
private bool PersistNewJiwaSalesOrder(Order order, SystemSettings systemSettings, List<IdMap> inventoryItemMaps, out string invoiceId)
{
Stopwatch stopwatch = new Stopwatch();
// {order} is the external sales order being imported
if (order != null && order.id.HasValue)
{
JiwaFinancials.Jiwa.JiwaSales.SalesOrder.SalesOrder salesOrder = JiwaManager.BusinessLogicFactory.CreateBusinessLogic<JiwaFinancials.Jiwa.JiwaSales.SalesOrder.SalesOrder>(null);
// Because this will separate web-sales
string debtorId= systemSettings.ResolveDebtorId();
// Because logical warehouse determines where the stock is taken from
string logicalWarehouseId = systemSettings.ResolveLogicalWarehouseId(jiwaManager);
jiwaSalesOrder.CreateNew(
SalesOrder.NewSalesOrderTypes.e_NewSalesOrder,
// ...and debtor is assigned now
debtorId, true,
string.Empty, string.Empty, string.Empty, // These two lines were added following your code snippet
logicalWarehouseId);
// Because it may be useful to attribute web-sales to a particular staff member
//jiwaSalesOrder.Staff.ReadRecord(systemSettings.ResolveJiwaStaffId(jiwaManager));
jiwaSalesOrder.InitiatedDate =
order.date_created.HasValue ?
order.date_created.Value :
DateTime.Now;
jiwaSalesOrder.Reference = order.id.Value.ToString();
// Because name and address are important
jiwaSalesOrder.CashSalesCompanyName = order.CompanyName();
if (string.IsNullOrEmpty(jiwaSalesOrder.CashSalesCompanyName))
{
jiwaSalesOrder.CashSalesName = order.CustomerName();
}
else
{
jiwaSalesOrder.CashSalesContactName = order.CustomerName();
}
// Because these must not be a mix of shipping and billing address details,
// AddressLines() is:
// an extension method that creates a list of strings
// from the external order shipping or billing addresses
List<string> addresses = order.AddressLines();
jiwaSalesOrder.CashSalesAddress1 = addresses[0];
jiwaSalesOrder.CashSalesAddress2 = addresses[1];
jiwaSalesOrder.CashSalesAddress3 = addresses[2];
jiwaSalesOrder.CashSalesAddress4 = addresses[3];
jiwaSalesOrder.CashSalesPostCode = addresses[4];
jiwaSalesOrder.CashSalesPhone = order.billing.phone;
// Because there will be order lines
foreach (OrderLineItem orderLineItem in Order.line_items)
{
decimal orderQuantity = orderLineItem.quantity ?? decimal.Zero;
decimal orderPrice = orderLineItem.price ?? decimal.Zero;
// Because an order line MUST have qty>0 and price>0 (our rule)
if (orderQuantity > decimal.Zero && orderPrice > decimal.Zero)
{
object newOrderLineKey = null;
// Because product id should be first choice
IdMap itemMap = inventoryItemMaps.FindFirstMatch(Constants.Entity.Product, orderLineItem.product_id.Value.ToString());
if (itemMap != null)
{
salesOrderLines.AddInventoryItem(itemMap.JiwaIdentity, SalesOrderLineCollection.SalesOrderLineInventorySeedTypes.e_SalesOrderLineInventoryID, ref newOrderLineKey);
}
else if (!string.IsNullOrEmpty(orderLineItem.sku)) // Their sku carries PartNo
{
salesOrderLines.AddInventoryItem(orderLineItem.sku, SalesOrderLineCollection.SalesOrderLineInventorySeedTypes.e_SalesOrderLinePartNo, ref newOrderLineKey);
}
// Because this means a line was added
if (newOrderLineKey != null)
{
// Because resolving this once is more effective
SalesOrderLine salesOrderLine = salesOrderLines[newOrderLineKey as string];
salesOrderLine.HiddenSetQuantityOrdered(ref orderQuantity);
salesOrderLine.HiddenSetDiscountedPrice(ref orderPrice);
}
}
}
if (salesOrder != null)
{
if (salesOrder.SalesOrderLines.Count.Equals(order.line_items.Count))
{
// Because this is "all lines"
logMessage =
string.Format(
Constants.Messages.Information.SalesOrderTransformSuccess,
order.id.Value, salesOrder.SalesOrderLines.Count,
methodName);
AddInformationLog(AerpSchema.Log.Directions.ToJiwa, 0, logMessage);
}
else
{
// Because this "only some lines"
logMessage =
string.Format(
Constants.Messages.Warning.SalesOrderTransformFailure,
order.id.Value,
salesOrder.SalesOrderLines.Count, order.line_items.Count,
methodName);
AddWarningLog(AerpSchema.Log.Directions.ToJiwa, 0, logMessage);
}
// Because the changes need to be persisted
stopwatch.Restart();
salesOrder.Save();
// Because the object needs to be fully populated by re-Reading
salesOrder.Read(salesOrder.RecID);
invoiceId = salesOrder.RecID;
// Because this is detail that may be a useful audit
stopwatch.Stop();
logMessage =
string.Format(
Constants.Messages.Verbose.ImportedSalesOrderSaved,
order.id.Value, salesOrder.InvoiceID,
methodName);
AddVerboseLog(AerpSchema.Log.Directions.ToJiwa, stopwatch.ElapsedMilliseconds, logMessage);
return true;
}
else
{
// Because this [shouldn't, but] may happen
logMessage =
string.Format(
Constants.Messages.Error.SalesOrderImportFailed,
order.id.Value, methodName);
AddErrorLog(AerpSchema.Log.Directions.ToJiwa, 0, logMessage);
}
}
else
{
// Because this should never happen...
logMessage =
string.Format(
Constants.Messages.Error.SalesOrderNotDefinedOrInvalid,
methodName);
AddErrorLog(AerpSchema.Log.Directions.ToJiwa, 0, logMessage);
}
invoiceId = string.Empty;
return false;
}
Some extra information?
The Add*Log() methods write rows in a Database table. Is this perhaps my issue?
If I check the Jiwa Manager.Database.SQLTransaction, it is null up to the Save() method being invoked. Checking after this is problematic because of the exception.