using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.JsonPatch; using AyaNova.Util; using AyaNova.Api.ControllerHelpers; using AyaNova.Models; namespace AyaNova.Biz { internal class WorkOrderBiz : BizObject, ISearchAbleObject { //Feature specific roles internal static AuthorizationRoles RolesAllowedToChangeSerial = AuthorizationRoles.BizAdminFull | AuthorizationRoles.DispatchFull | AuthorizationRoles.AccountingFull; internal WorkOrderBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles) { ct = dbcontext; UserId = currentUserId; UserTranslationId = userTranslationId; CurrentUserRoles = UserRoles; BizType = AyaType.WorkOrder; } internal static WorkOrderBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null) { if (httpContext != null) return new WorkOrderBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items)); else//when called internally for internal ops there will be no context so need to set default values for that return new WorkOrderBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdminFull); } //////////////////////////////////////////////////////////////////////////////////////////////// //EXISTS internal async Task ExistsAsync(long id) { return await ct.WorkOrder.AnyAsync(e => e.Id == id); } //////////////////////////////////////////////////////////////////////////////////////////////// /// GET /// /// internal async Task GetAsync(long fetchId, bool logTheGetEvent = true) { //This is simple so nothing more here, but often will be copying to a different output object or some other ops var ret = await ct.WorkOrder.SingleOrDefaultAsync(m => m.Id == fetchId); if (logTheGetEvent && ret != null) { //Log await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, fetchId, BizType, AyaEvent.Retrieved), ct); } return ret; } //////////////////////////////////////////////////////////////////////////////////////////////// //CREATE //Called from route and also seeder internal async Task CreateAsync(long? workorderTemplateId, long? customerId, uint? serial) { //Create and save to db a new workorder and return it //NOTE: Serial can be specified or edited after the fact in a limited way by full role specfic only!! (service manager, bizadminfull, accounting maybe) if (serial != null && !Authorized.HasAnyRole(CurrentUserRoles, RolesAllowedToChangeSerial)) { AddError(ApiErrorCode.NOT_AUTHORIZED, "Serial"); return null; } // await ValidateAsync(inObj, null); // if (HasErrors) // return null; // else // { //do stuff with WorkOrder WorkOrder o = new WorkOrder(); o.Serial = serial ?? ServerBootConfig.WORKORDER_SERIAL.GetNext(); //TODO: template //TODO: CUSTOMER ID //Save to db await ct.WorkOrder.AddAsync(o); await ct.SaveChangesAsync(); //Handle child and associated items: await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, o.Id, BizType, AyaEvent.Created), ct); await SearchIndexAsync(o, true); // await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, o.Tags, null); return o; //} } //////////////////////////////////////////////////////////////////////////////////////////////// //DUPLICATE // internal async Task DuplicateAsync(WorkOrder dbObj) { throw new System.NotImplementedException("STUB: WORKORDER DUPLICATE"); // WorkOrder outObj = new WorkOrder(); // CopyObject.Copy(dbObj, outObj, "Wiki"); // // outObj.Name = Util.StringUtil.NameUniquify(outObj.Name, 255); // //generate unique name // string newUniqueName = string.Empty; // bool NotUnique = true; // long l = 1; // do // { // newUniqueName = Util.StringUtil.UniqueNameBuilder(dbObj.Name, l++, 255); // NotUnique = await ct.WorkOrder.AnyAsync(m => m.Name == newUniqueName); // } while (NotUnique); // outObj.Name = newUniqueName; // outObj.Id = 0; // outObj.ConcurrencyToken = 0; // await ct.WorkOrder.AddAsync(outObj); // await ct.SaveChangesAsync(); // //Handle child and associated items: // await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, outObj.Id, BizType, AyaEvent.Created), ct); // await SearchIndexAsync(outObj, true); // await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, outObj.Tags, null); // return outObj; } //////////////////////////////////////////////////////////////////////////////////////////////// //UPDATE // //put internal async Task PutAsync(WorkOrder dbObj, WorkOrder putObj) { // make a snapshot of the original for validation but update the original to preserve workflow WorkOrder SnapshotOfOriginalDBObj = new WorkOrder(); CopyObject.Copy(dbObj, SnapshotOfOriginalDBObj); //Replace the db object with the PUT object CopyObject.Copy(putObj, dbObj, "Id,Serial"); //if user has rights then change it, otherwise just ignore it and do the rest if (SnapshotOfOriginalDBObj.Serial != putObj.Serial && Authorized.HasAnyRole(CurrentUserRoles, RolesAllowedToChangeSerial)) { dbObj.Serial = putObj.Serial; } dbObj.Tags = TagUtil.NormalizeTags(dbObj.Tags); dbObj.CustomFields = JsonUtil.CompactJson(dbObj.CustomFields); //Set "original" value of concurrency token to input token //this will allow EF to check it out ct.Entry(dbObj).OriginalValues["ConcurrencyToken"] = putObj.ConcurrencyToken; await ValidateAsync(dbObj, SnapshotOfOriginalDBObj); if (HasErrors) return false; //Log event and save context await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, dbObj.Id, BizType, AyaEvent.Modified), ct); await SearchIndexAsync(dbObj, false); await TagUtil.ProcessUpdateTagsInRepositoryAsync(ct, dbObj.Tags, SnapshotOfOriginalDBObj.Tags); return true; } private async Task SearchIndexAsync(WorkOrder obj, bool isNew) { //SEARCH INDEXING var SearchParams = new Search.SearchIndexProcessObjectParameters(UserTranslationId, obj.Id, BizType); SearchParams.AddText(obj.Notes).AddText(obj.Serial).AddText(obj.Wiki).AddText(obj.Tags).AddCustomFields(obj.CustomFields); if (isNew) await Search.ProcessNewObjectKeywordsAsync(SearchParams); else await Search.ProcessUpdatedObjectKeywordsAsync(SearchParams); } public async Task GetSearchResultSummary(long id) { var obj = await ct.WorkOrder.SingleOrDefaultAsync(m => m.Id == id); var SearchParams = new Search.SearchIndexProcessObjectParameters(); if (obj != null) SearchParams.AddText(obj.Notes).AddText(obj.Serial).AddText(obj.Wiki).AddText(obj.Tags).AddCustomFields(obj.CustomFields); return SearchParams; } //////////////////////////////////////////////////////////////////////////////////////////////// //DELETE // internal async Task DeleteAsync(WorkOrder dbObj) { throw new System.NotImplementedException("STUB: WORKORDER DELETE"); //Determine if the object can be deleted, do the deletion tentatively //Probably also in here deal with tags and associated search text etc //NOT REQUIRED NOW BUT IF IN FUTURE ValidateCanDelete(dbObj); // if (HasErrors) // return false; // ct.WorkOrder.Remove(dbObj); // await ct.SaveChangesAsync(); // //Log event // await EventLogProcessor.DeleteObjectLogAsync(UserId, BizType, dbObj.Id, dbObj.Serial.ToString(), ct); // await Search.ProcessDeletedObjectKeywordsAsync(dbObj.Id, BizType); // await TagUtil.ProcessDeleteTagsInRepositoryAsync(ct, dbObj.Tags); // return true; } //////////////////////////////////////////////////////////////////////////////////////////////// //VALIDATION // //Can save or update? private async Task ValidateAsync(WorkOrder proposedObj, WorkOrder currentObj) { //run validation and biz rules bool isNew = currentObj == null; // //Name required // if (string.IsNullOrWhiteSpace(proposedObj.Name)) // AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name"); // //Name must be less than 255 characters // if (proposedObj.Name.Length > 255) // AddError(ApiErrorCode.VALIDATION_LENGTH_EXCEEDED, "Name", "255 max"); // //If name is otherwise OK, check that name is unique // if (!PropertyHasErrors("Name")) // { // //Use Any command is efficient way to check existance, it doesn't return the record, just a true or false // if (await ct.WorkOrder.AnyAsync(m => m.Name == proposedObj.Name && m.Id != proposedObj.Id)) // { // AddError(ApiErrorCode.VALIDATION_NOT_UNIQUE, "Name"); // } // } //Any form customizations to validate? var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(x => x.FormKey == AyaType.WorkOrder.ToString()); if (FormCustomization != null) { //Yeppers, do the validation, there are two, the custom fields and the regular fields that might be set to required //validate users choices for required non custom fields RequiredFieldsValidator.Validate(this, FormCustomization, proposedObj); //validate custom fields CustomFieldsValidator.Validate(this, FormCustomization, proposedObj.CustomFields); } } //Can delete? // private void ValidateCanDelete(WorkOrder inObj) // { // //whatever needs to be check to delete this object // } //////////////////////////////////////////////////////////////////////////////////////////////// //JOB / OPERATIONS // //Other job handlers here... ///////////////////////////////////////////////////////////////////// }//eoc }//eons