From 96ff5141ec4ad775541e1f694d2511b803da5262 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Thu, 18 Feb 2021 01:31:25 +0000 Subject: [PATCH] --- server/AyaNova/biz/PurchaseOrderBiz.cs | 273 +++++++++++++-------- server/AyaNova/models/PurchaseOrderItem.cs | 1 + server/AyaNova/util/AySchema.cs | 2 +- 3 files changed, 179 insertions(+), 97 deletions(-) diff --git a/server/AyaNova/biz/PurchaseOrderBiz.cs b/server/AyaNova/biz/PurchaseOrderBiz.cs index 1bbcaf41..10cc9862 100644 --- a/server/AyaNova/biz/PurchaseOrderBiz.cs +++ b/server/AyaNova/biz/PurchaseOrderBiz.cs @@ -81,16 +81,17 @@ namespace AyaNova.Biz } PurchaseOrder newObject = new PurchaseOrder(); CopyObject.Copy(dbObject, newObject, "Wiki,Serial"); - foreach(var item in newObject.Items){ - item.QuantityReceived=0; - item.ReceivedCost=0; - item.ReceivedDate=null; - item.PurchaseOrderId=0; + foreach (var item in newObject.Items) + { + item.QuantityReceived = 0; + item.ReceivedCost = 0; + item.ReceivedDate = null; + item.PurchaseOrderId = 0; } newObject.Id = 0; newObject.Concurrency = 0; await ct.PurchaseOrder.AddAsync(newObject); - await ct.SaveChangesAsync(); + await ct.SaveChangesAsync(); await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); await SearchIndexAsync(newObject, true); await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); @@ -278,107 +279,187 @@ namespace AyaNova.Biz //A PO can now be edited in any way user wishes at any time so this method is to fix up //any changes they make in affected objects and inventory // - private async Task BizActionsAsync(AyaEvent ayaEvent, PurchaseOrder proposedObj, PurchaseOrder currentObj, IDbContextTransaction transaction) + private async Task BizActionsAsync(AyaEvent ayaEvent, PurchaseOrder newObj, PurchaseOrder oldObj, IDbContextTransaction transaction) { //MIGRATE_OUTSTANDING - woitempart request update //if received on woitempartrequest then need to update woitempartrequest (notification separate not a concern here) //if workorderitempartrequest item removed, need to fixup woitempartrequest //BUT *only* if the woitempartrequest still exists and isn't completed already + //todo: BizActionsAsync - handle user changing a part and/or warehouse in an item just as with quantity, forgot about that one + //todo: BizActionsAsync - VendorPartNumber automatically set this if teh vendorid has changed from the list of parts there is + //todo: if vendorid has changed, need to update all part values into poitems + + //Get inventory object for updating PartInventoryBiz pib = new PartInventoryBiz(ct, UserId, UserTranslationId, CurrentUserRoles); - switch (ayaEvent) + //DELETED + if (ayaEvent == AyaEvent.Deleted) { - case AyaEvent.Created: - { - //any received go into inventory - var inventoryAffectingItems = proposedObj.Items.Where(z => z.QuantityReceived > 0).ToList(); - foreach (var poItem in inventoryAffectingItems) - { - //make inventory adjustment here - dtPOPartInventory i = new dtPOPartInventory(); - i.PartId = poItem.PartId; - i.PartWarehouseId = poItem.PartWarehouseId; - i.Quantity = poItem.QuantityReceived; - i.SourceType = AyaType.PurchaseOrder; - i.SourceId = proposedObj.Id; - await pib.CreateAsync(i); + //REVERSE ENTIRE PO + //any received remove from inventory + var inventoryAffectingItems = oldObj.Items.Where(z => z.QuantityReceived > 0).ToList(); + foreach (var poItem in inventoryAffectingItems) + { + //make reversing inventory adjustment here + dtPOPartInventory i = new dtPOPartInventory(); + i.PartId = poItem.PartId; + i.PartWarehouseId = poItem.PartWarehouseId; + i.Quantity = poItem.QuantityReceived *= -1; + i.SourceType = AyaType.PurchaseOrder; + i.SourceId = newObj.Id; + await pib.CreateAsync(i); - //MIGRATE_OUTSTANDING - update workorderitempart here if applicable - } - } - break; - case AyaEvent.Modified: - { - //any changes that will affect inventory get processed here - foreach (var newItem in proposedObj.Items) - { - //get the matching currentPoItem - var oldItem = currentObj.Items.FirstOrDefault(z => z.Id == newItem.Id); - //NEW ITEM? - if (oldItem == null && newItem.QuantityReceived > 0) - { - //It's a new receipt with received amounts - add to inventory - dtPOPartInventory i = new dtPOPartInventory(); - i.PartId = newItem.PartId; - i.PartWarehouseId = newItem.PartWarehouseId; - i.Quantity = newItem.QuantityReceived; - i.SourceType = AyaType.PurchaseOrder; - i.SourceId = proposedObj.Id; - await pib.CreateAsync(i); - - //MIGRATE_OUTSTANDING - update workorderitempart here if applicable - } - //UPDATED ITEM WITH NEW RECEIVED AMOUNT? - else if (oldItem.QuantityReceived != newItem.QuantityReceived) - { - decimal netChange = 0; - if (oldItem.QuantityReceived < newItem.QuantityReceived) - { - //More received - netChange = newItem.QuantityReceived - oldItem.QuantityReceived; - } - else - { - //less received - netChange = newItem.QuantityReceived - oldItem.QuantityReceived; - } - - dtPOPartInventory i = new dtPOPartInventory(); - i.PartId = newItem.PartId; - i.PartWarehouseId = newItem.PartWarehouseId; - i.Quantity = netChange; - i.SourceType = AyaType.PurchaseOrder; - i.SourceId = proposedObj.Id; - await pib.CreateAsync(i); - - //MIGRATE_OUTSTANDING - update workorderitempart here if applicable - } - - } - } - break; - case AyaEvent.Deleted: - { - //REVERSE ENTIRE PO - //any received remove from inventory - var inventoryAffectingItems = currentObj.Items.Where(z => z.QuantityReceived > 0).ToList(); - foreach (var poItem in inventoryAffectingItems) - { - //make reversing inventory adjustment here - dtPOPartInventory i = new dtPOPartInventory(); - i.PartId = poItem.PartId; - i.PartWarehouseId = poItem.PartWarehouseId; - i.Quantity = poItem.QuantityReceived *= -1; - i.SourceType = AyaType.PurchaseOrder; - i.SourceId = proposedObj.Id; - await pib.CreateAsync(i); - - //MIGRATE_OUTSTANDING - update workorderitempart here if applicable - } - } - break; + //MIGRATE_OUTSTANDING - update workorderitempart here if applicable + } + return;//done, nothing more to do here } + + + //Some kind of update so fetch the parts so the default part values can be set on the poItem if necessary + var PoParts = await ct.Part.AsNoTracking().Where(x => newObj.Items.Any(z => z.PartId == x.Id)).ToListAsync(); + + //CREATED + if (ayaEvent == AyaEvent.Created) + { + //any received go into inventory + var inventoryAffectingItems = newObj.Items.Where(z => z.QuantityReceived > 0).ToList(); + foreach (var poItem in inventoryAffectingItems) + { + //make inventory adjustment here + dtPOPartInventory i = new dtPOPartInventory(); + i.PartId = poItem.PartId; + i.PartWarehouseId = poItem.PartWarehouseId; + i.Quantity = poItem.QuantityReceived; + i.SourceType = AyaType.PurchaseOrder; + i.SourceId = newObj.Id; + await pib.CreateAsync(i); + + //MIGRATE_OUTSTANDING - update workorderitempart here if applicable + } + + //All new so set them all + foreach (var poItem in newObj.Items) + SetPoItemDefaultPartValues(poItem, PoParts, newObj.VendorId); + return; + } + + //MODIFIED + if (ayaEvent == AyaEvent.Modified) + { + foreach (var newItem in newObj.Items) + { + //get the matching currentPoItem + var oldItem = oldObj.Items.FirstOrDefault(z => z.Id == newItem.Id); + + //NEW ITEM ADDED + if (oldItem == null) + { + if (newItem.QuantityReceived > 0) + { + //It's a new receipt with received amounts - add to inventory + dtPOPartInventory i = new dtPOPartInventory(); + i.PartId = newItem.PartId; + i.PartWarehouseId = newItem.PartWarehouseId; + i.Quantity = newItem.QuantityReceived; + i.SourceType = AyaType.PurchaseOrder; + i.SourceId = newObj.Id; + await pib.CreateAsync(i); + } + + SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId); + + //MIGRATE_OUTSTANDING - update workorderitempart here if applicable + continue;//on to next item + } + + //CHANGED PART OR WAREHOUSE ID + if (oldItem.PartId != newItem.PartId || oldItem.PartWarehouseId != newItem.PartWarehouseId) + { + + if (oldItem.QuantityReceived > 0) + { + //reverse inventory + dtPOPartInventory i = new dtPOPartInventory(); + i.PartId = oldItem.PartId; + i.PartWarehouseId = oldItem.PartWarehouseId; + i.Quantity = oldItem.QuantityReceived *= -1; + i.SourceType = AyaType.PurchaseOrder; + i.SourceId = newObj.Id; + await pib.CreateAsync(i); + } + + if (newItem.QuantityReceived > 0) + { + //set new inventory + dtPOPartInventory i = new dtPOPartInventory(); + i.PartId = newItem.PartId; + i.PartWarehouseId = newItem.PartWarehouseId; + i.Quantity = newItem.QuantityReceived; + i.SourceType = AyaType.PurchaseOrder; + i.SourceId = newObj.Id; + await pib.CreateAsync(i); + } + + //Update part values into poitem if the part or vendor has changed + if (oldItem.PartId != newItem.PartId || oldObj.VendorId != newObj.VendorId) + SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId); + + continue;//on to next item + } + + + //CHANGED ONLY THE RECEIVED AMOUNT + if (oldItem.QuantityReceived != newItem.QuantityReceived) + { + decimal netChange = 0; + if (oldItem.QuantityReceived < newItem.QuantityReceived) + netChange = newItem.QuantityReceived - oldItem.QuantityReceived;//More received + else + netChange = newItem.QuantityReceived - oldItem.QuantityReceived;//less received + + dtPOPartInventory i = new dtPOPartInventory(); + i.PartId = newItem.PartId; + i.PartWarehouseId = newItem.PartWarehouseId; + i.Quantity = netChange; + i.SourceType = AyaType.PurchaseOrder; + i.SourceId = newObj.Id; + await pib.CreateAsync(i); + + //MIGRATE_OUTSTANDING - update workorderitempart here if applicable + + //Update part values into poitem if the vendor has changed + if (oldObj.VendorId != newObj.VendorId) + SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId); + continue;//on to next + } + + + //CHANGED ONLY THE VENDOR + if (oldObj.VendorId != newObj.VendorId) + { + SetPoItemDefaultPartValues(newItem, PoParts, newObj.VendorId); + continue;//on to next + } + } + }//modified block + } + + //Called to update Part values into poitem like VendorNumber and costs etc + private void SetPoItemDefaultPartValues(PurchaseOrderItem poItem, List poParts, long vendorId) + { + var ThisPart = poParts.Single(x => x.Id == poItem.PartId);//part should always be there, if it isn't we have deeper problems + //VendorPartNumber + if (ThisPart.ManufacturerId == vendorId) + poItem.VendorPartNumber = ThisPart.ManufacturerNumber; + else if (ThisPart.WholeSalerId == vendorId) + poItem.VendorPartNumber = ThisPart.WholeSalerNumber; + else if (ThisPart.AlternativeWholeSalerId == vendorId) + poItem.VendorPartNumber = ThisPart.AlternativeWholeSalerNumber; + + //Cost + poItem.PurchaseOrderCost = ThisPart.Cost; + } diff --git a/server/AyaNova/models/PurchaseOrderItem.cs b/server/AyaNova/models/PurchaseOrderItem.cs index 79b65332..ca95962c 100644 --- a/server/AyaNova/models/PurchaseOrderItem.cs +++ b/server/AyaNova/models/PurchaseOrderItem.cs @@ -28,6 +28,7 @@ namespace AyaNova.Models public long? PartRequestedById { get; set; } public long? WorkorderItemPartRequestId { get; set; } public long? PurchaseTaxCodeId { get; set; } + public string VendorPartNumber { get; set; } [JsonIgnore] diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index 7a01d9ae..bee194a9 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -742,7 +742,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE"); await ExecQueryAsync("CREATE TABLE apurchaseorderitem (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, purchaseorderid BIGINT NOT NULL REFERENCES apurchaseorder ON DELETE CASCADE, " + "partid BIGINT NOT NULL REFERENCES apart, partwarehouseid BIGINT NOT NULL REFERENCES apartwarehouse, quantityordered DECIMAL(19,4) NOT NULL default 0, " + "quantityreceived DECIMAL(19,4) NOT NULL default 0, purchaseordercost DECIMAL(19,4) NOT NULL default 0, receivedcost DECIMAL(19,4) NOT NULL default 0, " + - "receiveddate TIMESTAMP, partrequestedbyid BIGINT REFERENCES auser, purchasetaxcodeid BIGINT REFERENCES ataxcode " + + "receiveddate TIMESTAMP, partrequestedbyid BIGINT REFERENCES auser, purchasetaxcodeid BIGINT REFERENCES ataxcode, vendorpartnumber TEXT " + ")");