diff --git a/server/AyaNova/biz/PartInventoryBiz.cs b/server/AyaNova/biz/PartInventoryBiz.cs index 0d2167c0..8a29af54 100644 --- a/server/AyaNova/biz/PartInventoryBiz.cs +++ b/server/AyaNova/biz/PartInventoryBiz.cs @@ -43,22 +43,22 @@ namespace AyaNova.Biz // internal async Task CreateAsync(PartInventory newObject) { - await ValidateAsync(newObject, null); + 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); - + return newObject; } } - + //////////////////////////////////////////////////////////////////////////////////////////////// //GET @@ -71,7 +71,7 @@ namespace AyaNova.Biz return ret; } - + //////////////////////////////////////////////////////////////////////////////////////////////// @@ -107,31 +107,76 @@ namespace AyaNova.Biz //VALIDATION // - private async Task ValidateAsync(PartInventory proposedObj, PartInventory currentObj) + private async Task ValidateAsync(PartInventory proposedObj) { - bool isNew = currentObj == null; - - //Name required - if (string.IsNullOrWhiteSpace(proposedObj.Name)) - AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name"); - - - - //If name is otherwise OK, check that name is unique - if (!PropertyHasErrors("Name")) + if (!await BizObjectExistsInDatabase.ExistsAsync(AyaType.Part, proposedObj.PartId, ct)) { - //Use Any command is efficient way to check existance, it doesn't return the record, just a true or false - if (await ct.PartInventory.AnyAsync(m => m.Name == proposedObj.Name && m.Id != proposedObj.Id)) - { - AddError(ApiErrorCode.VALIDATION_NOT_UNIQUE, "Name"); - } + AddError(ApiErrorCode.NOT_FOUND, "generalerror", $"PartInventory Part specified doesn't exist [id:{proposedObj.PartId}]"); + return; + } + + if (!await BizObjectExistsInDatabase.ExistsAsync(AyaType.PartWarehouse, proposedObj.PartWarehouseId, ct)) + { + AddError(ApiErrorCode.NOT_FOUND, "generalerror", $"PartInventory PartWarehouse specified doesn't exist [id:{proposedObj.PartWarehouseId}]"); + return; + } + + if (proposedObj.SourceType != AyaType.NoType && proposedObj.SourceId != 0 && !await BizObjectExistsInDatabase.ExistsAsync(proposedObj.SourceType, 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; } + /* + "CONSTRAINT UNQ_PartInventory UNIQUE (sourceid, sourcetype, entrydate, balance), " + + "CONSTRAINT UNQ_PartInventory_Previous_values UNIQUE (sourceid, sourcetype, lastentrydate, lastbalance), " + + "CONSTRAINT fk_PartInventory_self FOREIGN KEY (sourceid, sourcetype, lastentrydate, lastbalance) references apartinventory(sourceid, sourcetype, entrydate, balance), " + + "CONSTRAINT CHK_PartInventory_Valid_Balance CHECK(balance >= 0 AND (balance = COALESCE(lastbalance, 0) + quantity)), " + + "CONSTRAINT CHK_PartInventory_Valid_Dates_Sequence CHECK(lastentrydate < entrydate), " + + "CONSTRAINT CHK_PartInventory_Valid_Previous_Columns CHECK((lastentrydate IS NULL AND lastbalance IS NULL) OR (lastentrydate IS NOT NULL AND lastbalance IS NOT NULL)) " + + */ + + //New entry must have *something* to bank + if (proposedObj.Quantity == 0) + { + AddError(ApiErrorCode.VALIDATION_REQUIRED, "Quantity"); + return; + } + + //values must add up + if (proposedObj.LastBalance != null && proposedObj.Balance != proposedObj.LastBalance + proposedObj.Quantity) + { + AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Balance", "Balance incorrect (LastBalance + Quantity not equal to Balance"); + return; + } + + + //date is newer than last entry date? + if (proposedObj.LastEntryDate != null && proposedObj.LastEntryDate > proposedObj.EntryDate) + { + AddError(ApiErrorCode.VALIDATION_STARTDATE_AFTER_ENDDATE, "generalerror", "LastEntryDate is newer than EntryDate"); + return; + } + + //valid previous columns? + //either they're all null or none of them are null + + //fix and re-test + if (!((proposedObj.LastEntryDate == null + && proposedObj.LastBalance == null) || + (proposedObj.LastEntryDate != null + && proposedObj.LastBalance != null) + )) + { + AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "generalerror", "Last* entries must be all empty (opening entry) or none of them empty (any later entry)"); + return; + } + } - + //////////////////////////////////////////////////////////////////////////////////////////////// //REPORTING