|
|
@@ -16,6 +16,9 @@ using CsvHelper.TypeConversion;
|
|
|
using CsvHelper.Configuration;
|
|
|
using System.Reflection;
|
|
|
using System.Windows;
|
|
|
+using PRSDimensionUtils;
|
|
|
+using InABox.Clients;
|
|
|
+using InABox.Wpf;
|
|
|
|
|
|
namespace PRS.Shared
|
|
|
{
|
|
|
@@ -190,7 +193,7 @@ public class Module
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- public void ProcessLine(IDataModel<PurchaseOrder> model, PurchaseOrderItem purchaseOrderItem, PurchaseOrderTimberlineLine line)
|
|
|
+ public void ProcessLine(IDataModel<PurchaseOrder> model, PurchaseOrderItem purchaseOrderItem, PurchaseOrderItemAllocation? allocation, PurchaseOrderTimberlineLine line)
|
|
|
{
|
|
|
// Do extra processing for a purchase order line; return false to fail this purchase order
|
|
|
return true;
|
|
|
@@ -236,11 +239,21 @@ public class Module
|
|
|
.Add(x => x.TaxCode.Code)
|
|
|
.Add(x => x.Qty)
|
|
|
.Add(x => x.Cost)
|
|
|
- .Add(x => x.Dimensions.UnitSize)
|
|
|
.Add(x => x.IncTax)
|
|
|
- .Add(x => x.Job.JobNumber),
|
|
|
+ .Add(x => x.Job.JobNumber)
|
|
|
+ .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Data),
|
|
|
alias: "PurchaseOrder_PurchaseOrderItem");
|
|
|
|
|
|
+ model.AddChildTable<PurchaseOrderItem, PurchaseOrderItemAllocation>(x => x.ID, x => x.Item.ID,
|
|
|
+ isdefault: true,
|
|
|
+ columns: Columns.None<PurchaseOrderItemAllocation>()
|
|
|
+ .Add(x => x.ID)
|
|
|
+ .Add(x => x.PostedReference)
|
|
|
+ .Add(x => x.Item.ID)
|
|
|
+ .Add(x => x.Quantity)
|
|
|
+ .Add(x => x.Job.JobNumber),
|
|
|
+ parentalias: "PurchaseOrder_PurchaseOrderItem", childalias: "Allocations");
|
|
|
+
|
|
|
Script?.Execute(methodname: "BeforePost", parameters: new object[] { model });
|
|
|
return true;
|
|
|
}
|
|
|
@@ -249,9 +262,24 @@ public class Module
|
|
|
{
|
|
|
return Script?.Execute(methodname: "ProcessHeader", parameters: new object[] { model, purchaseOrder, header }) != false;
|
|
|
}
|
|
|
- private bool ProcessLine(IDataModel<PurchaseOrder> model, PurchaseOrderItem purchaseOrderItem, PurchaseOrderTimberlineLine line)
|
|
|
+ private bool ProcessLine(IDataModel<PurchaseOrder> model, PurchaseOrderItem purchaseOrderItem, PurchaseOrderItemAllocation? allocation, PurchaseOrderTimberlineLine line)
|
|
|
{
|
|
|
- return Script?.Execute(methodname: "ProcessLine", parameters: new object[] { model, purchaseOrderItem, line }) != false;
|
|
|
+ return Script?.Execute(methodname: "ProcessLine", parameters: new object?[] { model, purchaseOrderItem, allocation, line }) != false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private class LineData(PurchaseOrderItem poItem, double poCost, double poQty, StockDimensions poDim, IPostableFragment<PurchaseOrder> item, double qty)
|
|
|
+ {
|
|
|
+ public PurchaseOrderItem POItem { get; set; } = poItem;
|
|
|
+
|
|
|
+ public double POCost { get; set; } = poCost;
|
|
|
+
|
|
|
+ public double POQty { get; set; } = poQty;
|
|
|
+
|
|
|
+ public StockDimensions PODimensions { get; set; } = poDim;
|
|
|
+
|
|
|
+ public IPostableFragment<PurchaseOrder> Item { get; set; } = item;
|
|
|
+
|
|
|
+ public double Qty { get; set; } = qty;
|
|
|
}
|
|
|
|
|
|
private PurchaseOrderTimberlineResult DoProcess(IDataModel<PurchaseOrder> model)
|
|
|
@@ -260,6 +288,9 @@ public class Module
|
|
|
|
|
|
var lines = model.GetTable<PurchaseOrderItem>("PurchaseOrder_PurchaseOrderItem").ToObjects<PurchaseOrderItem>()
|
|
|
.GroupBy(x => x.PurchaseOrderLink.ID).ToDictionary(x => x.Key, x => x.ToList());
|
|
|
+ var allocations = model.GetTable<PurchaseOrderItemAllocation>("Allocations")
|
|
|
+ .ToObjects<PurchaseOrderItemAllocation>()
|
|
|
+ .GroupBy(x => x.Item.ID).ToDictionary(x => x.Key, x => x.ToList());
|
|
|
foreach (var purchaseOrder in model.GetTable<PurchaseOrder>().ToObjects<PurchaseOrder>())
|
|
|
{
|
|
|
var c = new PurchaseOrderTimberlineHeader
|
|
|
@@ -280,73 +311,120 @@ public class Module
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- // Dictionary from line number to POItem.
|
|
|
- var items = new Dictionary<int, PurchaseOrderItem>();
|
|
|
+ // Hashset of line numbers.
|
|
|
+ var items = new HashSet<int>();
|
|
|
var POItems = lines.GetValueOrDefault(purchaseOrder.ID)?.ToList() ?? new List<PurchaseOrderItem>();
|
|
|
- foreach (var purchaseOrderItem in POItems)
|
|
|
+
|
|
|
+ var lineData = new List<LineData>();
|
|
|
+
|
|
|
+ // Get the data for all the lines.
|
|
|
+ foreach(var poItem in POItems)
|
|
|
{
|
|
|
- if (int.TryParse(purchaseOrderItem.PostedReference, out var itemNumber))
|
|
|
+ // First, we must convert the dimensions and qty on the POItem to match the "exploded" allocations. Note we need to make copies,
|
|
|
+ // because we will be saving this poItem later on.
|
|
|
+ var dimensions = poItem.Dimensions.Copy();
|
|
|
+ var qty = DimensionUtils.ConvertDimensions(dimensions, poItem.Qty, Client<ProductDimensionUnit>.Provider);
|
|
|
+ var poCost = poItem.Cost;
|
|
|
+ var poQty = poItem.Qty;
|
|
|
+ if (!qty.IsEffectivelyEqual(poItem.Qty))
|
|
|
+ {
|
|
|
+ poCost = poItem.Cost * poItem.Qty / (qty.IsEffectivelyEqual(0.0) ? 1.0 : qty);
|
|
|
+ poQty = qty;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!allocations.TryGetValue(poItem.ID, out var poias))
|
|
|
{
|
|
|
- if (items.TryGetValue(itemNumber, out var oldItem))
|
|
|
+ poias = new();
|
|
|
+ }
|
|
|
+ var remQty = poItem.Qty - poias.Sum(x => x.Quantity);
|
|
|
+
|
|
|
+ if(remQty != 0)
|
|
|
+ {
|
|
|
+ lineData.Add(new(poItem, poCost, poQty, dimensions, poItem, remQty));
|
|
|
+ }
|
|
|
+ foreach(var poia in poias)
|
|
|
+ {
|
|
|
+ lineData.Add(new(poItem, poCost, poQty, dimensions, poia, poia.Quantity));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check line numbers.
|
|
|
+ foreach(var data in lineData)
|
|
|
+ {
|
|
|
+ if (int.TryParse(data.Item.PostedReference, out var itemNumber))
|
|
|
+ {
|
|
|
+ if (!items.Add(itemNumber))
|
|
|
{
|
|
|
// Theoretically shouldn't happen, but just in case.
|
|
|
- MessageBox.Show($"Warning: Multiple PurchaseOrder Items have the same line number for export; the line number for '{purchaseOrderItem.Description}' will be changed in the export.");
|
|
|
- Logger.Send(LogType.Error, "", $"Purchase Order Post: Multiple POItems with the same Line Number; changing line number of POItem {purchaseOrderItem.ID}");
|
|
|
- purchaseOrderItem.PostedReference = "";
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- items[itemNumber] = purchaseOrderItem;
|
|
|
+ MessageWindow.Warn(
|
|
|
+ $"Warning: Multiple PurchaseOrder Items have the same line number for export; the line number for '{data.POItem.Description}' will be changed in the export.");
|
|
|
+ Logger.Send(LogType.Error, "", $"Purchase Order Post: Multiple POItems with the same Line Number; changing line number of POItem {(data.Item as Entity)!.ID}");
|
|
|
+
|
|
|
+ data.Item.PostedReference = "";
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // Do post.
|
|
|
var success = true;
|
|
|
- foreach (var purchaseOrderItem in POItems)
|
|
|
+ foreach(var data in lineData)
|
|
|
{
|
|
|
- if (!int.TryParse(purchaseOrderItem.PostedReference, out var itemNumber))
|
|
|
+ if (!int.TryParse(data.Item.PostedReference, out var itemNumber))
|
|
|
{
|
|
|
itemNumber = 1;
|
|
|
- while (items.ContainsKey(itemNumber))
|
|
|
+ while (items.Contains(itemNumber))
|
|
|
{
|
|
|
++itemNumber;
|
|
|
}
|
|
|
|
|
|
- items[itemNumber] = purchaseOrderItem;
|
|
|
- purchaseOrderItem.PostedReference = itemNumber.ToString();
|
|
|
+ items.Add(itemNumber);
|
|
|
+ data.Item.PostedReference = itemNumber.ToString();
|
|
|
}
|
|
|
var ci = new PurchaseOrderTimberlineLine
|
|
|
{
|
|
|
CommitmentID = purchaseOrder.PONumber,
|
|
|
ItemNumber = itemNumber,
|
|
|
- Description = purchaseOrderItem.Description,
|
|
|
+ Description = data.POItem.Description,
|
|
|
// RetainagePercent = ,
|
|
|
- DeliveryDate = purchaseOrderItem.ReceivedDate,
|
|
|
+ DeliveryDate = data.POItem.ReceivedDate,
|
|
|
//ScopeOfWork
|
|
|
- Job = purchaseOrderItem.Job.JobNumber,
|
|
|
- //Extra = purchaseOrderItem.Job
|
|
|
- CostCode = purchaseOrderItem.CostCentre.Code,
|
|
|
- //Category = purchaseOrderItem.cat
|
|
|
- TaxGroup = purchaseOrderItem.TaxCode.Code,
|
|
|
- Units = Math.Round(purchaseOrderItem.Qty, 4),
|
|
|
- UnitCost = Math.Round(purchaseOrderItem.Cost, 4),
|
|
|
- UnitDescription = purchaseOrderItem.Dimensions.UnitSize,
|
|
|
- Amount = Math.Round(purchaseOrderItem.IncTax, 4),
|
|
|
+ //Extra = poItem.Job
|
|
|
+ //Category = poItem.cat
|
|
|
+ TaxGroup = data.POItem.TaxCode.Code,
|
|
|
+ Units = Math.Round(data.Qty, 4),
|
|
|
+ UnitCost = Math.Round(data.POCost, 4),
|
|
|
+ UnitDescription = data.PODimensions.UnitSize,
|
|
|
+ Amount = Math.Round(data.POItem.IncTax * data.Qty / data.POQty, 4),
|
|
|
// BoughtOut
|
|
|
};
|
|
|
|
|
|
- if(!ProcessLine(model, purchaseOrderItem, ci))
|
|
|
+ var alloc = data.Item as PurchaseOrderItemAllocation;
|
|
|
+ if(alloc is not null)
|
|
|
+ {
|
|
|
+ ci.Job = alloc.Job.JobNumber;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ci.Job = data.POItem.Job.JobNumber;
|
|
|
+ }
|
|
|
+ if (!ci.Job.IsNullOrWhiteSpace())
|
|
|
+ {
|
|
|
+ ci.CostCode = data.POItem.CostCentre.Code;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!ProcessLine(model, data.POItem, alloc, ci))
|
|
|
{
|
|
|
success = false;
|
|
|
break;
|
|
|
}
|
|
|
c.Lines.Add(ci);
|
|
|
}
|
|
|
+
|
|
|
if (success)
|
|
|
{
|
|
|
- foreach(var item in POItems)
|
|
|
+ foreach(var data in lineData)
|
|
|
{
|
|
|
- cs.AddFragment(item);
|
|
|
+ cs.AddFragment(data.Item);
|
|
|
}
|
|
|
cs.AddSuccess(purchaseOrder, c);
|
|
|
}
|