using Comal.Classes;
using InABox.Configuration;
using InABox.Core;
using InABox.DynamicGrid;
using InABox.WPF;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using InABox.WPF.Themes;
using NPOI.SS.Formula.Functions;
using System.Collections.ObjectModel;
using InABox.Clients;
using InABox.Wpf;
using InABox.Wpf.Reports;
using Columns = InABox.Core.Columns;
using PRSDesktop.Panels.ReservationManagement.TreatmentPO;
namespace PRSDesktop;
///
/// Interaction logic for JobRequisitionsPanel.xaml
///
public partial class ReservationManagementPanel : UserControl, IPanel
{
private ReservationManagementGlobalSettings _globalSettings = null!; // Initialised in Setup()
private DynamicSplitPanelView CurrentView;
private List PurchaseOrders = new List();
public ReservationManagementPanel()
{
InitializeComponent();
CurrentView = SplitPanel.View;
JobRequiItems.Reconfigure(options =>
{
var canMultiSelect = Mode != PanelMode.Reserve || SplitPanel.View == DynamicSplitPanelView.Master;
if(canMultiSelect)
{
options.MultiSelect = true;
}
else
{
options.MultiSelect = false;
}
});
}
enum PanelMode
{
Reserve,
Purchase
}
private PanelMode Mode { get; set; }
private void SelectDetailButton(Button button)
{
reserveBtn.Background = new SolidColorBrush(Colors.WhiteSmoke);
reserveBtn.Foreground = new SolidColorBrush(Colors.Black);
foreach(var btn in PurchaseOrderButtons.Children.OfType())
{
btn.Background = new SolidColorBrush(Colors.WhiteSmoke);
btn.Foreground = new SolidColorBrush(Colors.Black);
}
AddPOButton.Background = new SolidColorBrush(Colors.WhiteSmoke);
AddPOButton.Foreground = new SolidColorBrush(Colors.Black);
button.Background = ThemeManager.SelectedTabItemBackgroundBrush;
button.Foreground = ThemeManager.SelectedTabItemForegroundBrush;
}
private void Reconfigure()
{
JobRequiItems.Reconfigure();
OnUpdateDataModel?.Invoke(SectionName, DataModel(Selection.None));
}
private void SelectReserved()
{
SelectDetailButton(reserveBtn);
reserveCol.Width = new System.Windows.GridLength(1, System.Windows.GridUnitType.Star);
purchaseCol.Width = new System.Windows.GridLength(0);
if(Mode != PanelMode.Reserve)
{
Mode = PanelMode.Reserve;
Reconfigure();
}
}
private void SelectNewPurchaseOrder()
{
SelectDetailButton(AddPOButton);
reserveCol.Width = new System.Windows.GridLength(0);
purchaseCol.Width = new System.Windows.GridLength(1, System.Windows.GridUnitType.Star);
if (Mode != PanelMode.Purchase)
{
Mode = PanelMode.Purchase;
Reconfigure();
}
purchasing.LoadFromRequiLine(Guid.Empty);
}
private void SelectPurchaseOrder(Button button, PurchaseOrder order)
{
SelectDetailButton(button);
reserveCol.Width = new System.Windows.GridLength(0);
purchaseCol.Width = new System.Windows.GridLength(1, System.Windows.GridUnitType.Star);
if (Mode != PanelMode.Purchase)
{
Mode = PanelMode.Purchase;
Reconfigure();
}
purchasing.LoadFromRequiLine(order.ID);
}
public bool IsReady { get; set; }
public string SectionName => "Job Requisitions";
public event DataModelUpdateEvent? OnUpdateDataModel;
public void CreateToolbarButtons(IPanelHost host)
{
ProductSetupActions.Standard(host);
host.CreateSetupAction(new PanelAction() { Caption = "Reservation Management Settings", Image = PRSDesktop.Resources.specifications, OnExecute = ConfigSettingsClick });
// host.CreatePanelAction(new PanelAction("Treatment PO", PRSDesktop.Resources.purchase, TreatmentPO_Click));
if(Mode == PanelMode.Purchase && SplitPanel.IsDetailVisible())
{
var sectionName = SupplierPurchaseOrderPanel.SectionName;
var dataModel = SupplierPurchaseOrderPanel.DataModel(Array.Empty());
var reports = ReportUtils.LoadReports(sectionName, dataModel);
foreach(var report in reports)
{
host.CreateReport(PanelHost.CreateReportAction(report, (selection) =>
{
Guid[] ids;
if(selection == Selection.None)
{
ids = Array.Empty();
}
else
{
ids = PurchaseOrders.Select(x => x.ID).ToArray();
}
return SupplierPurchaseOrderPanel.DataModel(ids);
}));
}
}
}
private void ConfigSettingsClick(PanelAction obj)
{
var grid = new DynamicItemsListGrid();
if(grid.EditItems(new ReservationManagementGlobalSettings[] { _globalSettings }))
{
new GlobalConfiguration().Save(_globalSettings);
holdings.CompanyDefaultStyle = _globalSettings.ProductStyle;
JobRequiItems.DueDateAlert = _globalSettings.DueDateAlert;
JobRequiItems.DueDateWarning = _globalSettings.DueDateWarning;
}
}
public DataModel DataModel(Selection selection)
{
var ids = JobRequiItems.ExtractValues(x => x.ID, selection).ToArray();
return new BaseDataModel(new Filter(x => x.ID).InList(ids));
}
public void Heartbeat(TimeSpan time)
{
}
public void Refresh()
{
JobRequiItems.Refresh(false, true);
}
public Dictionary Selected()
{
return new Dictionary
{
[typeof(JobRequisitionItem).EntityName()] = JobRequiItems.SelectedRows
};
}
public void Setup()
{
SelectReserved();
JobRequiItems.OnSelectItem += OnJobRequiItemSelected;
JobRequiItems.Refresh(true, false);
_globalSettings = new GlobalConfiguration().Load();
substitutions.FreeStockOnly = JobRequiItems.UserSettings.SubstituteFreeStockOnly;
substitutions.UpdateStyle = JobRequiItems.UserSettings.SubstituteUpdateStyle;
JobRequiItems.DueDateAlert = _globalSettings.DueDateAlert;
JobRequiItems.DueDateWarning = _globalSettings.DueDateWarning;
holdings.CompanyDefaultStyle = _globalSettings.ProductStyle;
holdings.OnHoldingsReviewRefresh += Holdings_OnHoldingsReviewRefresh;
purchasing.OnPurchaseOrderSaved += Refresh;
}
private void OnJobRequiItemSelected(object sender, DynamicGridSelectionEventArgs e)
{
if (SplitPanel.IsDetailVisible())
{
holdings.Item = e.Rows?.FirstOrDefault()?.ToObject();
RefreshPurchaseOrderButtons();
}
}
private void RefreshPurchaseOrderButtons()
{
var requiIDs = JobRequiItems.SelectedRows
.Select(x => x.Get(x => x.ID))
.ToArray();
var pos = Client.Query(
new Filter(x => x.ID).InQuery(
new Filter(x => x.JobRequisitionItem.ID)
.InList(requiIDs),
x => x.PurchaseOrderItem.PurchaseOrderLink.ID),
Columns.None().Add(x => x.ID)
.Add(x => x.PONumber))
.ToObjects().ToList();
PurchaseOrders = pos;
PurchaseOrderButtons.Children.Clear();
var buttons = new List<(Button btn, PurchaseOrder po)>();
foreach (var po in pos)
{
var button = new Button
{
Content = po.PONumber,
Height = 30,
FontWeight = FontWeights.DemiBold,
BorderBrush = new SolidColorBrush(Colors.DarkGray),
BorderThickness = new Thickness(1.25),
Margin = new Thickness(2, 0, 0, 2),
Padding = new Thickness(13, 3, 13, 3)
};
button.Click += (o, e) =>
{
SelectPurchaseOrder(button, po);
};
buttons.Add((button, po));
PurchaseOrderButtons.Children.Add(button);
}
if (Mode == PanelMode.Purchase)
{
if (buttons.Count == 0)
{
SelectNewPurchaseOrder();
}
else
{
var btn = buttons[0];
SelectPurchaseOrder(btn.btn, btn.po);
}
}
else if (Mode == PanelMode.Reserve)
{
SelectReserved();
}
}
private void Holdings_OnHoldingsReviewRefresh()
{
Refresh();
}
private void CheckSaved(CancelEventArgs cancel)
{
if (!SplitPanel.IsDetailVisible() || !purchasing.EditorChanged)
{
return;
}
var result = MessageWindow.ShowYesNoCancel("You have changes that have not been saved; do you wish to save these changes?", "Save Changes?");
if (result == MessageWindowResult.Yes)
{
purchasing.Editor.SaveItem(cancel);
if (!cancel.Cancel)
{
MessageWindow.ShowMessage("Purchase Order saved.", "Success");
}
}
else if (result == MessageWindowResult.Cancel)
{
cancel.Cancel = true;
}
}
public void Shutdown(CancelEventArgs? cancel)
{
if(cancel is not null && purchasing.EditorChanged)
{
CheckSaved(cancel);
}
}
private void ReserveStock_Clicked(object sender, System.Windows.RoutedEventArgs e)
{
SelectReserved();
}
private void Purchasing_Drop(object sender, DragEventArgs e)
{
if(DynamicGridUtils.TryGetDropData(e, out var type, out var table))
{
if(type == typeof(JobRequisitionItem))
{
purchasing.DropItems(table.Rows);
}
}
}
private void AddPOButton_Click(object sender, RoutedEventArgs e)
{
SelectNewPurchaseOrder();
}
private void TreatmentPO_Click(PanelAction action)
{
var jris = JobRequiItems.SelectedRows.ToObjects().ToDictionary(x => x.ID);
if(jris.Count == 0)
{
MessageWindow.ShowMessage("Please select at least one job requisition item.", "No items selected");
return;
}
if(jris.Values.Any(x => x.TreatmentRequired - x.TreatmentOnOrder <= 0))
{
MessageWindow.ShowMessage("Please select only items requiring treatment.", "Already treated");
return;
}
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.Values, Columns.None()
.Add(x => x.Product.Code)
.Add(x => x.Product.Name)
.Add(x => x.Requisition.Number)
.Add(x => x.Job.JobNumber)
.Add(x => x.Dimensions.Value));
// Here, we grab every stock movement for the selected JRIs, and group them per JRI. For each JRI, any stock movements that are in the wrong style
// are grouped according to their holding key. Note that this mimics precisely the TreatmentRequired aggregate on JRI. Hence, these holdings represent
// the TreatmentRequired amounts; the 'Units' field is equivalent to TreatmentRequired.
var holdings = Client.Query(
new Filter(x => x.JobRequisitionItem.ID).InList(jris.Keys.ToArray()),
Columns.None()
.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()
.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(x => x.ID).InList(jris.Values.Select(x => x.Style.ID).ToArray()),
Columns.None()
.Add(x => x.ID)
.Add(x => x.Code)
.Add(x => x.StockTreatmentProduct.ID))
.ToObjects().ToDictionary(x => x.ID);
// We need to load the treatment product for the styles that we need.
var treatmentProducts = Client.Query(
new Filter(x => x.ID).InList(styles.Select(x => x.Value.StockTreatmentProduct.ID).ToArray()),
Columns.None()
.Add(x => x.ID)
.Add(x => x.Code)
.Add(x => x.Name)
.Add(x => x.Supplier.ID)
.Add(x => x.TreatmentType.ID)
.Add(x => x.TreatmentType.Description)
.Add(x => x.TreatmentType.Calculation))
.ToObjects().ToDictionary(x => x.ID);
// Also, the ProductTreatment contains the parameter we need.
var jriProductsParameters = Client.Query(
new Filter(x => x.Product.ID).InList(jris.Values.Select(x => x.Product.ID).ToArray()),
Columns.None()
.Add(x => x.Product.ID)
.Add(x => x.TreatmentType.ID)
.Add(x => x.Parameter))
.ToObjects().ToDictionary(x => (x.Product.ID, x.TreatmentType.ID));
var items = new List();
foreach(var (id, jri) in jris)
{
if (!styles.TryGetValue(jri.Style.ID, out var style))
{
continue;
}
if(!treatmentProducts.TryGetValue(style.StockTreatmentProduct.ID, out var treatmentProduct))
{
MessageWindow.ShowMessage($"No stock treatment product found for style {style.Code}", "Treatment product not found");
return;
}
else if(treatmentProduct.TreatmentType.ID == Guid.Empty)
{
MessageWindow.ShowMessage($"Treatment product {treatmentProduct.Code} does not have a treatment type", "No treatment type");
return;
}
if(!jriProductsParameters.TryGetValue((jri.Product.ID, treatmentProduct.TreatmentType.ID), out var treatment))
{
MessageWindow.ShowMessage(
$"No treatment parameter found for product {jri.Product.Code} for treatment type {treatmentProduct.TreatmentType.Description}",
"Treatment product not found");
return;
}
var jriHoldings = holdings.GetValueOrDefault(id);
// We know here that the TreatmentRequired > 0, because of the check at the top of the function. Hence, there definitely should be holdings.
// This therefore shouldn't ever happen, but if it does, we've made a logic mistake, and this error will tell us that.
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())
{
// This is the default calculation.
multiplier = treatment.Parameter * jri.Dimensions.Value;
}
else
{
var model = new TreatmentTypeCalculationModel();
model.Dimensions.CopyFrom(jri.Dimensions);
model.Parameter = treatment.Parameter;
var expression = new CoreExpression(treatmentProduct.TreatmentType.Calculation);
if(!expression.Evaluate(model).Get(out multiplier, out var e))
{
MessageWindow.ShowError("Error calculating expression multiplier; using Parameter * Dimensions.Value instead.", e);
multiplier = treatment.Parameter * jri.Dimensions.Value;
}
}
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;
// holding.Units should be TreatmentRequired
item.RequiredQuantity = holding.Units;
items.Add(item);
}
}
var window = new ReservationManagementTreatmentOrderScreen(items);
if(window.ShowDialog() == true)
{
var orders = new List>>();
var movements = new List();
var results = window.Results.GroupBy(x => x.Supplier.ID).Select(x => (x.Key, x.ToArray())).ToArray();
var suppliers = Client.Query(
new Filter(x => x.ID).InList(results.ToArray(x => x.Key)),
Columns.None().Add(x => x.ID).Add(x => x.DefaultLocation.ID))
.ToObjects()
.ToDictionary(x => x.ID);
foreach(var (supplierID, perSupplier) in results)
{
var order = new PurchaseOrder();
order.RaisedBy.ID = App.EmployeeID;
order.DueDate = DateTime.Today.AddDays(7);
order.Notes = [$"Treatment purchase order raised by {App.EmployeeName} from Reservation Management screen"];
LookupFactory.DoLookup(order, x => x.SupplierLink, supplierID);
var orderItems = new List<(PurchaseOrderItem, JobRequisitionItemLink)>();
foreach(var item in perSupplier)
{
var orderItem = new PurchaseOrderItem();
orderItem.Product.ID = item.Item.TreatmentProduct.ID;
orderItem.Job.ID = item.Item.JRI.Job.ID;
orderItems.Add((orderItem, item.Item.JRI));
}
LookupFactory.DoLookups(
orderItems.Select(x => new Tuple(x.Item1, x.Item1.Product.ID)),
x => x.Product);
LookupFactory.DoLookups(
orderItems.Select(x => new Tuple(x.Item1, x.Item1.Job.ID)),
x => x.Job);
LookupFactory.DoLookups(
orderItems.WithIndex().Select(x => new Tuple(x.Value.Item1, perSupplier[x.Key].SupplierProduct.TaxCode.ID)),
x => x.TaxCode);
foreach (var (i, item) in perSupplier.WithIndex())
{
var orderItem = orderItems[i].Item1;
orderItem.Qty = item.Quantity;
orderItem.Cost = item.SupplierProduct.CostPrice * item.Item.Multiplier;
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 doIssue = false;
if(Security.IsAllowed())
{
if (_globalSettings.AutoIssueTreatmentPOs)
{
doIssue = true;
}
else if(MessageWindow.ShowYesNo($"Do you wish to mark the purchase order{(orders.Count != 1 ? "s" : "")} as issued?", "Mark as issued?"))
{
doIssue = true;
}
}
if (doIssue)
{
foreach(var (order, _) in orders)
{
order.IssuedBy.ID = App.EmployeeID;
order.IssuedDate = DateTime.Now;
}
}
Client.Save(orders.Select(x => x.Item1), "Treatment PO created from Reservation Management screen");
foreach(var (order, orderItems) in orders)
{
foreach(var item in orderItems)
{
item.Item1.PurchaseOrderLink.ID = order.ID;
}
}
Client.Save(orders.SelectMany(x => x.Item2).Select(x => x.Item1), "Treatment PO created from Reservation Management screen");
Client.Save(orders.SelectMany(x => x.Item2).Select(x =>
{
var jriPOI = new JobRequisitionItemPurchaseOrderItem();
jriPOI.JobRequisitionItem.ID = x.Item2.ID;
jriPOI.PurchaseOrderItem.ID = x.Item1.ID;
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" : "")} {(doIssue ? "issued" : "raised")}:\n" +
$"- {string.Join(',', orders.Select(x => x.Item1.PONumber))}",
"Success");
JobRequiItems.SelectedRows = [];
JobRequiItems.Refresh(false, true);
}
}
private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
{
JobRequiItems.Reconfigure();
if(CurrentView != e.View)
{
CurrentView = e.View;
if (e.View != DynamicSplitPanelView.Master)
{
Refresh();
}
}
}
private bool _updatingSubstitution = false;
private void JobRequiItems_OnOnSelectItem(object sender, DynamicGridSelectionEventArgs e)
{
_updatingSubstitution = true;
try
{
var row = e.Rows?.SingleOrDefault();
var visible =
row != null
&& row.Get(x => x.InStock).IsEffectivelyEqual(0.0)
&& row.Get(x => x.TotalOrders).IsEffectivelyEqual(0.0)
&& row.Get(x => x.OnOrder).IsEffectivelyEqual(0.0)
&& row.Get(x => x.TreatmentRequired).IsEffectivelyEqual(0.0)
&& row.Get(x => x.TreatmentOnOrder).IsEffectivelyEqual(0.0)
&& row.Get(x => x.Allocated).IsEffectivelyEqual(0.0)
&& row.Get(x => x.PickRequested).IsEffectivelyEqual(0.0)
&& row.Get(x => x.Issued).IsEffectivelyEqual(0.0);
substitutions.SizeChanged -= Substitutions_OnSizeChanged;
SubstitutionSplitterRow.Height = visible ? GridLength.Auto : new GridLength(0.0);
SubstitutionRow.Height = visible ? new GridLength(JobRequiItems.UserSettings.SubstitutionGridHeight) : new GridLength(0.0);
SubstitutionButtonRow.Height = visible ? GridLength.Auto : new GridLength(0.0);
substitutions.SizeChanged += Substitutions_OnSizeChanged;
if (visible)
substitutions.JRI = row?.ToObject() ?? new JobRequisitionItem();
SubstitutionFreeStock.IsChecked = JobRequiItems.UserSettings.SubstituteFreeStockOnly;
SubstitutionUpdateStyle.IsChecked = JobRequiItems.UserSettings.SubstituteUpdateStyle;
}
finally
{
_updatingSubstitution = false;
}
}
private void SubstitutionFreeStock_OnChecked(object sender, RoutedEventArgs e)
{
if (_updatingSubstitution)
return;
substitutions.FreeStockOnly = SubstitutionFreeStock.IsChecked == true;
JobRequiItems.UserSettings.SubstituteFreeStockOnly = substitutions.FreeStockOnly;
new UserConfiguration().Save(JobRequiItems.UserSettings);
}
private void SubstitutionUpdateStyle_OnChecked(object sender, RoutedEventArgs e)
{
if (_updatingSubstitution)
return;
substitutions.UpdateStyle = SubstitutionUpdateStyle.IsChecked == true;
JobRequiItems.UserSettings.SubstituteUpdateStyle = substitutions.UpdateStyle;
new UserConfiguration().Save(JobRequiItems.UserSettings);
}
private bool _sizeChanging = false;
private void Substitutions_OnSizeChanged(object sender, SizeChangedEventArgs e)
{
_sizeChanging = System.Windows.Input.Mouse.LeftButton == MouseButtonState.Pressed;
}
protected override void OnPreviewMouseUp(MouseButtonEventArgs e)
{
base.OnPreviewMouseUp(e);
if (_sizeChanging)
{
_sizeChanging = false;
JobRequiItems.UserSettings.SubstitutionGridHeight = substitutions.ActualHeight;
new UserConfiguration().Save(JobRequiItems.UserSettings);
}
}
private void ChangeProduct_OnClick(object sender, RoutedEventArgs e)
{
var _holding = substitutions.SelectedRows?.FirstOrDefault()?.ToObject();
var _jrirow = JobRequiItems.SelectedRows.FirstOrDefault();
if (_holding == null || _jrirow == null)
return;
var _jri = _jrirow.ToObject();
_jri.Dimensions.CopyFrom(_holding.Dimensions, true);
if (substitutions.UpdateStyle)
_jri.Style.CopyFrom(_holding.Style);
Client.Save(_jri,"Substituted by Requisition Management Screen");
var _xferout = _holding.CreateMovement();
_xferout.Issued = Math.Min(_holding.Available, _jri.Qty);
_xferout.Notes = "Substituted by Requisition Management Screen";
_xferout.Transaction = Guid.NewGuid();
_xferout.Type = StockMovementType.TransferOut;
var _xferin = _holding.CreateMovement();
_xferin.JobRequisitionItem.CopyFrom(_jri);
_xferin.Job.CopyFrom(_jri.Job);
_xferin.Received = Math.Min(_holding.Available, _jri.Qty);
_xferin.Notes = "Substituted by Requisition Management Screen";
_xferin.Transaction = _xferout.Transaction;
_xferin.Type = StockMovementType.TransferIn;
Client.Save(new[] { _xferout, _xferin}, "Substituted by Requisition Management Screen");
JobRequiItems.Refresh(false,true);
// Allocate Stock (transfer if required)
}
private void Substitutions_OnOnSelectItem(object sender, DynamicGridSelectionEventArgs e)
{
ChangeProduct.IsEnabled = e.Rows?.SingleOrDefault() != null;
}
}