using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Comal.Classes; using InABox.Core; namespace Comal.Stores { internal class PurchaseOrderItemStore : BaseStore { private void UpdateStockMovements(PurchaseOrderItem entity) { if (!entity.Product.IsValid()) { Logger.Send(LogType.Information, UserID, "PurchaseOrderItem.Product.ID is blank!"); return; } var locationid = entity.StockLocation.ID; var locationValid = entity.StockLocation.IsValid(); var movementtask = new Task>(() => { var result = Provider.Query( new Filter(x => x.OrderItem.ID).IsEqualTo(entity.ID), new Columns( x => x.ID, x => x.Date, x => x.Product.ID, x => x.Received, x => x.Employee.ID, x => x.OrderItem.ID, x => x.Job.ID, x => x.Location.ID, x => x.Dimensions.Unit.ID, x => x.Dimensions.Unit.Formula, x => x.Dimensions.Unit.Format, x => x.Dimensions.Quantity, x => x.Dimensions.Length, x => x.Dimensions.Width, x => x.Dimensions.Height, x => x.Dimensions.Weight, x => x.Notes, x => x.Cost, x => x.Dimensions.Unit.HasHeight, x => x.Dimensions.Unit.HasLength, x => x.Dimensions.Unit.HasWidth, x => x.Dimensions.Unit.HasWeight, x => x.Dimensions.Unit.HasQuantity, x => x.Dimensions.Unit.Formula, x => x.Dimensions.Unit.Format, x => x.Dimensions.Unit.Code, x => x.Dimensions.Unit.Description ) ).Rows.Select(x => x.ToObject()).ToList(); if (!result.Any()) result.Add(new StockMovement()); return result; }); movementtask.Start(); var producttask = new Task(() => { return Provider.Query( new Filter(x => x.ID).IsEqualTo(entity.Product.ID), new Columns( x => x.ID, x => x.DefaultLocation.ID, x => x.Warehouse.ID, x => x.Dimensions.Unit.ID, x => x.Dimensions.Unit.Formula, x => x.Dimensions.Unit.Format, x => x.Dimensions.Quantity, x => x.Dimensions.Length, x => x.Dimensions.Width, x => x.Dimensions.Height, x => x.Dimensions.Weight, x => x.NonStock, x => x.Dimensions.Unit.HasHeight, x => x.Dimensions.Unit.HasLength, x => x.Dimensions.Unit.HasWidth, x => x.Dimensions.Unit.HasWeight, x => x.Dimensions.Unit.HasQuantity, x => x.Dimensions.Unit.Formula, x => x.Dimensions.Unit.Format, x => x.Dimensions.Unit.Code, x => x.Dimensions.Unit.Description, x => x.TotalStock, x => x.AverageCost ) ).Rows.FirstOrDefault(); }); producttask.Start(); var locationtask = new Task(() => { return Provider.Query( new Filter(x => x.Default).IsEqualTo(true), new Columns(x => x.ID, x => x.Warehouse.ID, x => x.Warehouse.Default) ); }); locationtask.Start(); Task.WaitAll(movementtask, producttask, locationtask); var movements = movementtask.Result; var productrow = producttask.Result; var defaultlocations = locationtask.Result; if (entity.Qty == 0) { Logger.Send(LogType.Information, UserID, "PurchaseOrderItem Qty is blank!"); return; } if (productrow == null) { Logger.Send(LogType.Information, UserID, "Cannot Find PurchaseOrderItem.Product.ID!"); return; } if (productrow.Get(x => x.NonStock)) { Logger.Send(LogType.Information, UserID, "PurchaseOrderItem.Product is marked as Non Stock!"); return; } if (!locationValid) { Logger.Send(LogType.Information, UserID, "PurchaseOrderItem.Location.ID is blank!"); if (productrow != null) { var productlocationid = productrow.EntityLinkID(x => x.DefaultLocation) ?? Guid.Empty; if (productlocationid != Guid.Empty) { Logger.Send(LogType.Information, UserID, "- Using Product.DefaultLocation.ID as location"); locationid = productlocationid; } else { var productwarehouseid = productrow.Get(c => c.Warehouse.ID); var row = defaultlocations.Rows.FirstOrDefault(r => r.Get(c => c.Warehouse.ID) == productwarehouseid); if (row != null) { Logger.Send(LogType.Information, UserID, "- Using Product.Warehouse -> Default as location"); locationid = row.Get(x => x.ID); } } } if (locationid == Guid.Empty) { var row = defaultlocations.Rows.FirstOrDefault(r => r.Get(c => c.Warehouse.Default)); if (row != null) { Logger.Send(LogType.Information, UserID, "- Using Default Warehouse -> Default Location as location"); locationid = row.Get(x => x.ID); } } if (locationid == Guid.Empty) { Logger.Send(LogType.Information, UserID, "- Cannot find Location : Skipping Movement Creation"); return; } } if ( (entity.Dimensions.Unit.ID == Guid.Empty) && (entity.Dimensions.Height == 0) && (entity.Dimensions.Width == 0) && (entity.Dimensions.Length == 0) && (entity.Dimensions.Weight == 0) ) { Logger.Send(LogType.Information, UserID, "PurchaseOrderItem.Unit Size is zero!"); entity.Dimensions.CopyFrom(productrow.ToObject().Dimensions); } var product = productrow.ToObject(); var poqty = entity.Qty * (Math.Abs(entity.Dimensions.Value) > 0.0001F ? entity.Dimensions.Value : 1.0F); var pocost = entity.Cost * entity.Qty; var totalqty = product.TotalStock + poqty; var totalcost = (product.TotalStock * product.AverageCost) + pocost; var averagecost = Math.Abs(totalqty) > 0.0001F ? totalcost / totalqty : pocost / poqty; if (Math.Abs(averagecost - product.AverageCost) > 0.0001F) { product.AverageCost = averagecost; FindSubStore().Save(product,"Updated Average Cost"); } foreach (var movement in movements) { movement.Batch.Type = StockMovementBatchType.Receipt; movement.Date = entity.ReceivedDate; movement.Product.ID = entity.Product.ID; movement.Received = entity.Qty; movement.Employee.ID = Guid.Empty; movement.OrderItem.ID = entity.ID; movement.Job.ID = entity.Job.ID; movement.Location.ID = locationid; movement.Style.ID = entity.Style.ID; movement.Style.Code = entity.Style.Code; movement.Style.Description = entity.Style.Description; movement.Notes = string.Format("Received on PO {0}", entity.PurchaseOrderLink.PONumber); movement.Cost = entity.Cost; movement.Dimensions.Unit.ID = entity.Dimensions.Unit.ID; movement.Dimensions.Height = entity.Dimensions.Height; movement.Dimensions.Length = entity.Dimensions.Length; movement.Dimensions.Width = entity.Dimensions.Width; movement.Dimensions.Weight = entity.Dimensions.Weight; movement.Dimensions.Quantity = entity.Dimensions.Quantity; movement.Dimensions.UnitSize = entity.Dimensions.UnitSize; movement.Dimensions.Value = entity.Dimensions.Value; movement.Dimensions.UnitSize = entity.Dimensions.UnitSize; } var updates = movements.Where(x => x.IsChanged()); if (updates.Any()) FindSubStore().Save(updates, "Updated by Purchase Order Modification"); } private void DeleteStockMovements(PurchaseOrderItem entity) { var movements = Provider.Query( new Filter(x => x.OrderItem.ID).IsEqualTo(entity.ID), new Columns(x => x.ID) ).Rows.Select(x => x.ToObject()); if (movements.Any()) FindSubStore().Delete(movements, "Purchase Order Item marked as Unreceived"); } protected override void AfterSave(PurchaseOrderItem entity) { base.AfterSave(entity); if (entity.ReceivedDate.IsEmpty() && entity.HasOriginalValue("RecievedDate")) { if(DateTime.Parse(entity.OriginalValues["RecievedDate"].ToString()) != entity.ReceivedDate) DeleteStockMovements(entity); } else if(!entity.ReceivedDate.IsEmpty()) { UpdateStockMovements(entity); UpdateJobRequiItems(entity); } } private void UpdateJobRequiItems(PurchaseOrderItem entity) { var table = Provider.Query( new Filter(x => x.PurchaseOrderItem.ID).IsEqualTo(entity.ID), new Columns(x => x.ID, x => x.Status) ); if (table.Rows.Any()) { JobRequisitionItem item = table.Rows.FirstOrDefault().ToObject(); if (item.Status == JobRequisitionItemStatus.TreatmentOnOrder) item.Status = JobRequisitionItemStatus.TreatmentReceived; else item.Status = JobRequisitionItemStatus.Received; Provider.Save(item); } } protected override void BeforeDelete(PurchaseOrderItem entity) { base.BeforeDelete(entity); DeleteStockMovements(entity); } protected override void AfterDelete(PurchaseOrderItem entity) { base.AfterDelete(entity); RemoveJobRequisitionItemLink(entity); } private void RemoveJobRequisitionItemLink(PurchaseOrderItem entity) { CoreTable table = Provider.Query ( new Filter(x => x.PurchaseOrderItem.ID).IsEqualTo(entity.ID), new Columns(x => x.ID, x => x.PurchaseOrderItem.PurchaseOrderLink.PONumber, x => x.Status) ); if (table.Rows.Any()) { JobRequisitionItem item = table.Rows.FirstOrDefault().ToObject(); item.PurchaseOrderItem.PurchaseOrderLink.PONumber = ""; item.Status = JobRequisitionItemStatus.NotChecked; Provider.Save(item); } } } }