|
@@ -340,28 +340,75 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
|
|
|
private void TreatmentPO_Click(PanelAction action)
|
|
|
{
|
|
|
- var jris = JobRequiItems.SelectedRows.ToArray<JobRequisitionItem>();
|
|
|
- if(jris.Length == 0)
|
|
|
+ var jris = JobRequiItems.SelectedRows.ToObjects<JobRequisitionItem>().ToDictionary(x => x.ID);
|
|
|
+ if(jris.Count == 0)
|
|
|
{
|
|
|
MessageWindow.ShowMessage("Please select at least one job requisition item.", "No items selected");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- if(jris.Any(x => x.TreatmentRequired - x.TreatmentOnOrder <= 0))
|
|
|
+ if(jris.Values.Any(x => x.TreatmentRequired - x.TreatmentOnOrder <= 0))
|
|
|
{
|
|
|
MessageWindow.ShowMessage("Please select only items requiring treatment.", "Already treated");
|
|
|
return;
|
|
|
}
|
|
|
- if(jris.Any(x => x.Style.ID == Guid.Empty))
|
|
|
+ if(jris.Values.Any(x => x.Style.ID == Guid.Empty))
|
|
|
{
|
|
|
MessageWindow.ShowMessage("Please select only items with a style.", "No style");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- Client.EnsureColumns(jris, Columns.None<JobRequisitionItem>().Add(x => x.Product.Name));
|
|
|
+ Client.EnsureColumns(jris.Values, Columns.None<JobRequisitionItem>().Add(x => x.Product.Name));
|
|
|
+
|
|
|
+ var holdings = Client.Query(
|
|
|
+ new Filter<StockMovement>(x => x.JobRequisitionItem.ID).InList(jris.Keys.ToArray()),
|
|
|
+ Columns.None<StockMovement>()
|
|
|
+ .Add(x => x.JobRequisitionItem.ID)
|
|
|
+ .Add(x => x.Job.ID)
|
|
|
+ .Add(x => x.Job.JobNumber)
|
|
|
+ .Add(x => x.Job.Name)
|
|
|
+ .Add(x => x.Product.ID)
|
|
|
+ .Add(x => x.Product.Code)
|
|
|
+ .Add(x => x.Product.Name)
|
|
|
+ .Add(x => x.Location.ID)
|
|
|
+ .Add(x => x.Location.Code)
|
|
|
+ .Add(x => x.Location.Description)
|
|
|
+ .Add(x => x.Style.ID)
|
|
|
+ .Add(x => x.Style.Code)
|
|
|
+ .Add(x => x.Style.Description)
|
|
|
+ .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local)
|
|
|
+ .Add(x => x.Units))
|
|
|
+ .ToObjects<StockMovement>()
|
|
|
+ .GroupBy(x => x.JobRequisitionItem.ID)
|
|
|
+ .ToDictionary(x => x.Key, x =>
|
|
|
+ {
|
|
|
+ var jri = jris[x.Key];
|
|
|
+ return x.Where(x => x.Style.ID != jri.Style.ID).GroupBy(x => new
|
|
|
+ {
|
|
|
+ Job = x.Job.ID,
|
|
|
+ Product = x.Product.ID,
|
|
|
+ Location = x.Location.ID,
|
|
|
+ Style = x.Style.ID,
|
|
|
+ x.Dimensions
|
|
|
+ }).ToDictionary(
|
|
|
+ x => x.Key,
|
|
|
+ x =>
|
|
|
+ {
|
|
|
+ var items = x.ToArray();
|
|
|
+ return new
|
|
|
+ {
|
|
|
+ Job = items[0].Job,
|
|
|
+ Product = items[0].Product,
|
|
|
+ Location = items[0].Location,
|
|
|
+ Style = items[0].Style,
|
|
|
+ Dimensions = items[0].Dimensions,
|
|
|
+ Units = items.Sum(x => x.Units)
|
|
|
+ };
|
|
|
+ });
|
|
|
+ });
|
|
|
|
|
|
var styles = Client.Query(
|
|
|
- new Filter<ProductStyle>(x => x.ID).InList(jris.ToArray(x => x.Style.ID)),
|
|
|
+ new Filter<ProductStyle>(x => x.ID).InList(jris.Values.Select(x => x.Style.ID).ToArray()),
|
|
|
Columns.None<ProductStyle>()
|
|
|
.Add(x => x.ID)
|
|
|
.Add(x => x.Code)
|
|
@@ -379,7 +426,7 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
.Add(x => x.TreatmentType.Calculation))
|
|
|
.ToObjects<Product>().ToDictionary(x => x.ID);
|
|
|
var jriProductsParameters = Client.Query(
|
|
|
- new Filter<ProductTreatment>(x => x.Product.ID).InList(jris.ToArray(x => x.Product.ID)),
|
|
|
+ new Filter<ProductTreatment>(x => x.Product.ID).InList(jris.Values.Select(x => x.Product.ID).ToArray()),
|
|
|
Columns.None<ProductTreatment>()
|
|
|
.Add(x => x.Product.ID)
|
|
|
.Add(x => x.TreatmentType.ID)
|
|
@@ -388,7 +435,7 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
|
|
|
var items = new List<ReservationManagementTreatmentPOItem>();
|
|
|
|
|
|
- foreach(var jri in jris)
|
|
|
+ foreach(var (id, jri) in jris)
|
|
|
{
|
|
|
if (!styles.TryGetValue(jri.Style.ID, out var style))
|
|
|
{
|
|
@@ -412,14 +459,17 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- var item = new ReservationManagementTreatmentPOItem();
|
|
|
- item.Product.CopyFrom(treatmentProduct);
|
|
|
- item.Style.CopyFrom(style);
|
|
|
- item.JRI.CopyFrom(jri);
|
|
|
+ var jriHoldings = holdings.GetValueOrDefault(id);
|
|
|
+ if(jriHoldings is null || jriHoldings.Count == 0)
|
|
|
+ {
|
|
|
+ MessageWindow.ShowError($"Internal error for requisition {jri.Requisition.Number} for job {jri.Job.JobNumber}", $"No holdings even though TreatmentRequired is greater than 0.");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
+ double multiplier;
|
|
|
if (treatmentProduct.TreatmentType.Calculation.IsNullOrWhiteSpace())
|
|
|
{
|
|
|
- item.Multiplier = treatment.Parameter * jri.Dimensions.Value;
|
|
|
+ multiplier = treatment.Parameter * jri.Dimensions.Value;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
@@ -428,27 +478,50 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
model.Parameter = treatment.Parameter;
|
|
|
|
|
|
var expression = new CoreExpression<TreatmentTypeCalculationModel, double>(treatmentProduct.TreatmentType.Calculation);
|
|
|
- if(expression.Evaluate(model).Get(out var multiplier, out var e))
|
|
|
- {
|
|
|
- item.Multiplier = multiplier;
|
|
|
- }
|
|
|
- else
|
|
|
+ if(!expression.Evaluate(model).Get(out multiplier, out var e))
|
|
|
{
|
|
|
MessageWindow.ShowError("Error calculating expression multiplier; using Parameter * Dimensions.Value instead.", e);
|
|
|
- item.Multiplier = treatment.Parameter * jri.Dimensions.Value;
|
|
|
+ multiplier = treatment.Parameter * jri.Dimensions.Value;
|
|
|
}
|
|
|
}
|
|
|
- item.RequiredQuantity = jri.TreatmentRequired - jri.TreatmentOnOrder;
|
|
|
|
|
|
- items.Add(item);
|
|
|
+ foreach(var (key, holding) in jriHoldings)
|
|
|
+ {
|
|
|
+ if (!holding.Units.IsEffectivelyGreaterThan(0)) continue;
|
|
|
+
|
|
|
+ var item = new ReservationManagementTreatmentPOItem();
|
|
|
+ item.Product.CopyFrom(holding.Product);
|
|
|
+ item.Style.CopyFrom(holding.Style);
|
|
|
+ item.Job.CopyFrom(holding.Job);
|
|
|
+ item.Location.CopyFrom(holding.Location);
|
|
|
+ item.Dimensions.CopyFrom(holding.Dimensions);
|
|
|
+
|
|
|
+ item.TreatmentProduct.CopyFrom(treatmentProduct);
|
|
|
+ item.Finish.CopyFrom(style);
|
|
|
+
|
|
|
+ item.JRI.CopyFrom(jri);
|
|
|
+
|
|
|
+ item.Multiplier = multiplier;
|
|
|
+ item.RequiredQuantity = holding.Units;// jri.TreatmentRequired - jri.TreatmentOnOrder;
|
|
|
+
|
|
|
+ items.Add(item);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
var window = new ReservationManagementTreatmentOrderScreen(items);
|
|
|
if(window.ShowDialog() == true)
|
|
|
{
|
|
|
var orders = new List<Tuple<PurchaseOrder, List<(PurchaseOrderItem, JobRequisitionItemLink)>>>();
|
|
|
+ var movements = new List<StockMovement>();
|
|
|
|
|
|
- foreach(var perSupplier in window.Results.GroupBy(x => x.Supplier.ID))
|
|
|
+ var results = window.Results.GroupBy(x => x.Supplier.ID).Select(x => (x.Key, x.ToArray())).ToArray();
|
|
|
+ var suppliers = Client.Query(
|
|
|
+ new Filter<Supplier>(x => x.ID).InList(results.ToArray(x => x.Key)),
|
|
|
+ Columns.None<Supplier>().Add(x => x.ID).Add(x => x.DefaultLocation.ID))
|
|
|
+ .ToObjects<Supplier>()
|
|
|
+ .ToDictionary(x => x.ID);
|
|
|
+
|
|
|
+ foreach(var (supplierID, perSupplier) in results)
|
|
|
{
|
|
|
var order = new PurchaseOrder();
|
|
|
order.RaisedBy.ID = App.EmployeeID;
|
|
@@ -456,14 +529,13 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
order.DueDate = DateTime.Today.AddDays(7);
|
|
|
order.Notes = [$"Treatment purchase order raised by {App.EmployeeName} from Reservation Management screen"];
|
|
|
|
|
|
- LookupFactory.DoLookup<PurchaseOrder, Supplier, SupplierLink>(order, x => x.SupplierLink, perSupplier.Key);
|
|
|
+ LookupFactory.DoLookup<PurchaseOrder, Supplier, SupplierLink>(order, x => x.SupplierLink, supplierID);
|
|
|
|
|
|
var orderItems = new List<(PurchaseOrderItem, JobRequisitionItemLink)>();
|
|
|
- var results = perSupplier.ToArray();
|
|
|
- foreach(var item in results)
|
|
|
+ foreach(var item in perSupplier)
|
|
|
{
|
|
|
var orderItem = new PurchaseOrderItem();
|
|
|
- orderItem.Product.ID = item.Item.Product.ID;
|
|
|
+ orderItem.Product.ID = item.Item.TreatmentProduct.ID;
|
|
|
orderItem.Job.ID = item.Item.JRI.Job.ID;
|
|
|
|
|
|
orderItems.Add((orderItem, item.Item.JRI));
|
|
@@ -476,10 +548,10 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
orderItems.Select(x => new Tuple<PurchaseOrderItem, Guid>(x.Item1, x.Item1.Job.ID)),
|
|
|
x => x.Job);
|
|
|
LookupFactory.DoLookups<PurchaseOrderItem, TaxCode, TaxCodeLink>(
|
|
|
- orderItems.WithIndex().Select(x => new Tuple<PurchaseOrderItem, Guid>(x.Value.Item1, results[x.Key].SupplierProduct.TaxCode.ID)),
|
|
|
+ orderItems.WithIndex().Select(x => new Tuple<PurchaseOrderItem, Guid>(x.Value.Item1, perSupplier[x.Key].SupplierProduct.TaxCode.ID)),
|
|
|
x => x.TaxCode);
|
|
|
|
|
|
- foreach(var (i, item) in results.WithIndex())
|
|
|
+ foreach (var (i, item) in perSupplier.WithIndex())
|
|
|
{
|
|
|
var orderItem = orderItems[i].Item1;
|
|
|
orderItem.Qty = item.Quantity;
|
|
@@ -487,22 +559,64 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
orderItem.Description = $"Treatment for {item.Item.JRI.Product.Name} ({item.Item.Product.Code}/{item.Item.Product.Name})";
|
|
|
}
|
|
|
|
|
|
+ if(suppliers.TryGetValue(supplierID, out var supplier))
|
|
|
+ {
|
|
|
+ foreach(var item in perSupplier)
|
|
|
+ {
|
|
|
+ var tOut = new StockMovement();
|
|
|
+ tOut.Job.CopyFrom(item.Item.Job);
|
|
|
+ tOut.Style.CopyFrom(item.Item.Style);
|
|
|
+ tOut.Location.CopyFrom(item.Item.Location);
|
|
|
+ tOut.Product.CopyFrom(item.Item.Product);
|
|
|
+ tOut.Dimensions.CopyFrom(item.Item.Dimensions);
|
|
|
+
|
|
|
+ tOut.Employee.ID = App.EmployeeID;
|
|
|
+ tOut.Date = DateTime.Now;
|
|
|
+ tOut.Issued = item.Quantity;
|
|
|
+ tOut.Type = StockMovementType.TransferOut;
|
|
|
+ tOut.JobRequisitionItem.CopyFrom(item.Item.JRI);
|
|
|
+ tOut.Notes = "Stock movement for treatment purchase order created from Reservation Management";
|
|
|
+
|
|
|
+ var tIn = tOut.CreateMovement();
|
|
|
+ tIn.Transaction = tOut.Transaction;
|
|
|
+
|
|
|
+ tIn.Style.CopyFrom(item.Item.JRI.Style);
|
|
|
+ tIn.Location.CopyFrom(supplier.DefaultLocation);
|
|
|
+
|
|
|
+ tIn.Employee.ID = App.EmployeeID;
|
|
|
+ tIn.Date = tOut.Date;
|
|
|
+ tIn.Received = item.Quantity;
|
|
|
+ tIn.Type = StockMovementType.TransferIn;
|
|
|
+ tIn.JobRequisitionItem.CopyFrom(item.Item.JRI);
|
|
|
+ tIn.Notes = "Stock movement for treatment purchase order created from Reservation Management";
|
|
|
+
|
|
|
+ movements.Add(tOut);
|
|
|
+ movements.Add(tIn);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ MessageWindow.ShowMessage(
|
|
|
+ $"No default location set up for supplier '{perSupplier[0].Supplier.Code}'; skipping creating stock movements",
|
|
|
+ "No default location");
|
|
|
+ }
|
|
|
+
|
|
|
orders.Add(new(order, orderItems));
|
|
|
}
|
|
|
|
|
|
- var issue = false;
|
|
|
+ var doIssue = false;
|
|
|
if(Security.IsAllowed<CanIssueTreatmentPurchaseOrders>())
|
|
|
{
|
|
|
if (_globalSettings.AutoIssueTreatmentPOs)
|
|
|
{
|
|
|
- issue = true;
|
|
|
+ doIssue = true;
|
|
|
}
|
|
|
else if(MessageWindow.ShowYesNo($"Do you wish to mark the purchase order{(orders.Count != 1 ? "s" : "")} as issued?", "Mark as issued?"))
|
|
|
{
|
|
|
- issue = true;
|
|
|
+ doIssue = true;
|
|
|
}
|
|
|
}
|
|
|
- if (issue)
|
|
|
+ if (doIssue)
|
|
|
{
|
|
|
foreach(var (order, _) in orders)
|
|
|
{
|
|
@@ -528,8 +642,10 @@ public partial class ReservationManagementPanel : UserControl, IPanel<JobRequisi
|
|
|
return jriPOI;
|
|
|
}), "Treatment PO created from Reservation Management screen");
|
|
|
|
|
|
+ Client.Save(movements, "Treatment PO created from Reservation Management screen");
|
|
|
+
|
|
|
MessageWindow.ShowMessage(
|
|
|
- $"{orders.Count} treatment purchase order{(orders.Count != 1 ? "s" : "")} {(issue ? "issued" : "raised")}:\n" +
|
|
|
+ $"{orders.Count} treatment purchase order{(orders.Count != 1 ? "s" : "")} {(doIssue ? "issued" : "raised")}:\n" +
|
|
|
$"- {string.Join(',', orders.Select(x => x.Item1.PONumber))}",
|
|
|
"Success");
|
|
|
|