From 13a71d643faa2a022b2a1f7a1879d6ce2f27fe9f Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Tue, 16 Feb 2021 19:10:50 +0000 Subject: [PATCH] --- server/AyaNova/biz/PartInventoryBiz.cs | 88 ++++++++--------- server/AyaNova/biz/PurchaseOrderBiz.cs | 125 ++++++++++++++++--------- 2 files changed, 128 insertions(+), 85 deletions(-) diff --git a/server/AyaNova/biz/PartInventoryBiz.cs b/server/AyaNova/biz/PartInventoryBiz.cs index 49cc2faf..64d9762c 100644 --- a/server/AyaNova/biz/PartInventoryBiz.cs +++ b/server/AyaNova/biz/PartInventoryBiz.cs @@ -9,6 +9,7 @@ using AyaNova.Models; using Newtonsoft.Json.Linq; using System.Collections.Generic; using Newtonsoft.Json; +using Microsoft.EntityFrameworkCore.Storage; namespace AyaNova.Biz { @@ -41,54 +42,57 @@ namespace AyaNova.Biz //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE (adjustment version) // - internal async Task CreateAsync(dtPartInventory newDtObject) + internal async Task CreateAsync(dtPartInventory newDtObject, IDbContextTransaction parentTransaction = null) { - using (var transaction = await ct.Database.BeginTransactionAsync()) + IDbContextTransaction transaction = null; + if (parentTransaction == null) + transaction = await ct.Database.BeginTransactionAsync(); + + try { - try + //get the last record if exists (will not if opening balance) + var LastEntry = await ct.PartInventory.OrderByDescending(m => m.EntryDate).FirstOrDefaultAsync(m => m.PartId == newDtObject.PartId && m.PartWarehouseId == newDtObject.PartWarehouseId); + PartInventory newObject = new PartInventory(); + newObject.Description = newDtObject.Description; + newObject.EntryDate = DateTime.UtcNow; + newObject.PartId = newDtObject.PartId; + newObject.PartWarehouseId = newDtObject.PartWarehouseId; + newObject.SourceId = null; + newObject.SourceType = null; + newObject.Quantity = newDtObject.Quantity; + + if (LastEntry != null) { - //get the last record if exists (will not if opening balance) - var LastEntry = await ct.PartInventory.OrderByDescending(m => m.EntryDate).FirstOrDefaultAsync(m => m.PartId == newDtObject.PartId && m.PartWarehouseId == newDtObject.PartWarehouseId); - PartInventory newObject = new PartInventory(); - newObject.Description = newDtObject.Description; - newObject.EntryDate = DateTime.UtcNow; - newObject.PartId = newDtObject.PartId; - newObject.PartWarehouseId = newDtObject.PartWarehouseId; - newObject.SourceId = null; - newObject.SourceType = null; - newObject.Quantity = newDtObject.Quantity; - - if (LastEntry != null) - { - newObject.LastEntryDate = LastEntry.EntryDate; - newObject.LastBalance = LastEntry.Balance; - newObject.Balance = LastEntry.Balance + newObject.Quantity; - } - else - { - newObject.Balance = newObject.Quantity; - } - - await ValidateAsync(newObject); - if (HasErrors) - return null; - else - { - - await ct.PartInventory.AddAsync(newObject); - await ct.SaveChangesAsync(); - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); - await SearchIndexAsync(newObject, true); - await transaction.CommitAsync(); - return newObject; - } + newObject.LastEntryDate = LastEntry.EntryDate; + newObject.LastBalance = LastEntry.Balance; + newObject.Balance = LastEntry.Balance + newObject.Quantity; } - catch + else { - //Just re-throw for now, let exception handler deal, but in future may want to deal with this more here - throw; + newObject.Balance = newObject.Quantity; + } + + await ValidateAsync(newObject); + if (HasErrors) + return null; + else + { + await ct.PartInventory.AddAsync(newObject); + await ct.SaveChangesAsync(); + //all good do the commit if it's ours + if (parentTransaction == null) + await transaction.CommitAsync(); + await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); + await SearchIndexAsync(newObject, true); + return newObject; } } + catch + { + //Just re-throw for now, let exception handler deal, but in future may want to deal with this more here + throw; + } + } @@ -183,7 +187,7 @@ namespace AyaNova.Biz } if (proposedObj.SourceType != null && proposedObj.SourceId != null && !await BizObjectExistsInDatabase.ExistsAsync((AyaType)proposedObj.SourceType, (long)proposedObj.SourceId, ct)) - { + { AddError(ApiErrorCode.NOT_FOUND, "generalerror", $"PartInventory source object causing inventory change specified doesn't exist [type:{proposedObj.SourceType}, id:{proposedObj.SourceId}]"); return; } diff --git a/server/AyaNova/biz/PurchaseOrderBiz.cs b/server/AyaNova/biz/PurchaseOrderBiz.cs index 3ac81d35..bd714a74 100644 --- a/server/AyaNova/biz/PurchaseOrderBiz.cs +++ b/server/AyaNova/biz/PurchaseOrderBiz.cs @@ -48,16 +48,21 @@ namespace AyaNova.Biz return null; else { - await BizActionsAsync(newObject, null); - newObject.Tags = TagBiz.NormalizeTags(newObject.Tags); - newObject.CustomFields = JsonUtil.CompactJson(newObject.CustomFields); - await ct.PurchaseOrder.AddAsync(newObject); - 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); - await HandlePotentialNotificationEvent(AyaEvent.Created, newObject); - return newObject; + using (var transaction = await ct.Database.BeginTransactionAsync()) + { + + newObject.Tags = TagBiz.NormalizeTags(newObject.Tags); + newObject.CustomFields = JsonUtil.CompactJson(newObject.CustomFields); + await ct.PurchaseOrder.AddAsync(newObject); + await BizActionsAsync(AyaEvent.Created, newObject, null, transaction); + await ct.SaveChangesAsync(); + await transaction.CommitAsync(); + await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct); + await SearchIndexAsync(newObject, true); + await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null); + await HandlePotentialNotificationEvent(AyaEvent.Created, newObject); + return newObject; + } } } @@ -114,32 +119,33 @@ namespace AyaNova.Biz AddError(ApiErrorCode.CONCURRENCY_CONFLICT); return null; } - putObject.Tags = TagBiz.NormalizeTags(putObject.Tags); putObject.CustomFields = JsonUtil.CompactJson(putObject.CustomFields); await ValidateAsync(putObject, dbObject); if (HasErrors) return null; - - await BizActionsAsync(putObject, dbObject); - - ct.Replace(dbObject, putObject); - try + using (var transaction = await ct.Database.BeginTransactionAsync()) { - await ct.SaveChangesAsync(); + await BizActionsAsync(AyaEvent.Modified, putObject, dbObject, transaction); + ct.Replace(dbObject, putObject); + try + { + await ct.SaveChangesAsync(); + await transaction.CommitAsync(); + } + catch (DbUpdateConcurrencyException) + { + if (!await ExistsAsync(putObject.Id)) + AddError(ApiErrorCode.NOT_FOUND); + else + AddError(ApiErrorCode.CONCURRENCY_CONFLICT); + return null; + } + await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); + await SearchIndexAsync(putObject, false); + await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, putObject.Tags, dbObject.Tags); + await HandlePotentialNotificationEvent(AyaEvent.Modified, putObject, dbObject); + return putObject; } - catch (DbUpdateConcurrencyException) - { - if (!await ExistsAsync(putObject.Id)) - AddError(ApiErrorCode.NOT_FOUND); - else - AddError(ApiErrorCode.CONCURRENCY_CONFLICT); - return null; - } - await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObject.Id, BizType, AyaEvent.Modified), ct); - await SearchIndexAsync(putObject, false); - await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, putObject.Tags, dbObject.Tags); - await HandlePotentialNotificationEvent(AyaEvent.Modified, putObject, dbObject); - return putObject; } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -161,6 +167,7 @@ namespace AyaNova.Biz if (HasErrors) return false; ct.PurchaseOrder.Remove(dbObject); + await BizActionsAsync(AyaEvent.Deleted, null, dbObject, transaction); await ct.SaveChangesAsync(); await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObject.Id, dbObject.Serial.ToString(), ct); await Search.ProcessDeletedObjectKeywordsAsync(dbObject.Id, BizType, ct); @@ -246,6 +253,7 @@ namespace AyaNova.Biz private async Task ValidateCanDeleteAsync(PurchaseOrder inObj) { + //only if none received right? Or do we allow it and just reverse the whole shebang? await Task.CompletedTask; } @@ -255,10 +263,33 @@ namespace AyaNova.Biz //BIZ ACTIONS // - private async Task BizActionsAsync(PurchaseOrder proposedObj, PurchaseOrder currentObj) + private async Task BizActionsAsync(AyaEvent ayaEvent, PurchaseOrder proposedObj, PurchaseOrder currentObj, Microsoft.EntityFrameworkCore.Storage.IDbContextTransaction transaction) { //TODO: BIZ ACTIONS TO FIXUP INVENTORY ON CHANGES ETC + //If received now less than before need to take out of inventory + //If received now more than before need to put into inventory + + //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 + + switch (ayaEvent) + { + 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 + + } + break; + case AyaEvent.Modified: + break; + case AyaEvent.Deleted: + break; + } + await Task.CompletedTask; } @@ -413,20 +444,14 @@ namespace AyaNova.Biz { var p = (PurchaseOrder)proposedObj; var c = (PurchaseOrder)currentObj; - //PartRequestReceived event? + + //# PartRequestReceived { //get a list of all items with part requests and received inventory var proposedRequestItems = p.Items.Where(z => z.WorkorderItemPartRequestId != null && z.QuantityReceived != 0); //are there any potential notify items? if (proposedRequestItems.Count() > 0) { - List subs = null; - //are any of them new, or a change from before? - - // var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.PartRequestReceived).ToListAsync(); - - - //Look for new receipts of requested parts foreach (var proposedRequestItem in proposedRequestItems) { @@ -437,15 +462,29 @@ namespace AyaNova.Biz { //is there a subscriber for this user id and event? var sub = await ct.NotifySubscription.FirstOrDefaultAsync(z => z.EventType == NotifyEventType.PartRequestReceived && z.UserId == proposedRequestItem.PartRequestedById); + if (sub != null) + { + //yes. So we have a subscriber, a change in received for a request, time to notify + //not for inactive users + if (!await UserBiz.UserIsActive(sub.UserId)) continue; + NotifyEvent n = new NotifyEvent() + { + EventType = NotifyEventType.PartRequestReceived, + UserId = sub.UserId, + AyaType = AyaType.WorkOrderItemPartRequest, + ObjectId = (long)proposedRequestItem.WorkorderItemPartRequestId, + NotifySubscriptionId = sub.Id, + Name = BizObjectNameFetcherDirect.Name(AyaType.WorkOrderItemPartRequest, (long)proposedRequestItem.WorkorderItemPartRequestId, ct) + }; + await ct.NotifyEvent.AddAsync(n); + log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]"); + await ct.SaveChangesAsync(); + } } - - } - } } - } }//end of process notifications