372 lines
18 KiB
C#
372 lines
18 KiB
C#
// using System;
|
|
// using System.Threading.Tasks;
|
|
// using Microsoft.EntityFrameworkCore;
|
|
// using System.Linq;
|
|
// using AyaNova.Util;
|
|
// using AyaNova.Api.ControllerHelpers;
|
|
// using Microsoft.Extensions.Logging;
|
|
// using AyaNova.Models;
|
|
// using Newtonsoft.Json.Linq;
|
|
// using System.Collections.Generic;
|
|
|
|
// namespace AyaNova.Biz
|
|
// {
|
|
// internal class ServiceBankBiz : BizObject, ISearchAbleObject, IReportAbleObject, IExportAbleObject, INotifiableObject
|
|
// {
|
|
// internal ServiceBankBiz(AyContext dbcontext, long currentUserId, long userTranslationId, AuthorizationRoles UserRoles)
|
|
// {
|
|
// ct = dbcontext;
|
|
// UserId = currentUserId;
|
|
// UserTranslationId = userTranslationId;
|
|
// CurrentUserRoles = UserRoles;
|
|
// BizType = AyaType.ServiceBank;
|
|
// }
|
|
|
|
// internal static ServiceBankBiz GetBiz(AyContext ct, Microsoft.AspNetCore.Http.HttpContext httpContext = null)
|
|
// {
|
|
// if (httpContext != null)
|
|
// return new ServiceBankBiz(ct, UserIdFromContext.Id(httpContext.Items), UserTranslationIdFromContext.Id(httpContext.Items), UserRolesFromContext.Roles(httpContext.Items));
|
|
// else
|
|
// return new ServiceBankBiz(ct, 1, ServerBootConfig.AYANOVA_DEFAULT_TRANSLATION_ID, AuthorizationRoles.BizAdmin);
|
|
// }
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //EXISTS
|
|
// internal async Task<bool> ExistsAsync(long id)
|
|
// {
|
|
// return await ct.ServiceBank.AnyAsync(z => z.Id == id);
|
|
// }
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //CREATE
|
|
// //
|
|
// internal async Task<ServiceBank> CreateAsync(dtServiceBank newDtObject)
|
|
// {
|
|
// using (var transaction = await ct.Database.BeginTransactionAsync())
|
|
// {
|
|
// //get the last record
|
|
// var LastEntry = await ct.ServiceBank.OrderByDescending(m => m.EntryDate).FirstOrDefaultAsync(m => m.ObjectId == newDtObject.ObjectId && m.AType == newDtObject.AType);
|
|
// ServiceBank newObject = new ServiceBank();
|
|
// newObject.Name = newDtObject.Name;
|
|
// newObject.EntryDate = DateTime.UtcNow;
|
|
// newObject.ObjectId = newDtObject.ObjectId;
|
|
// newObject.AType = newDtObject.AType;
|
|
// newObject.SourceId = newDtObject.SourceId;
|
|
// newObject.SourceType = newDtObject.SourceType;
|
|
// newObject.Incidents = newDtObject.Incidents;
|
|
// newObject.Currency = newDtObject.Currency;
|
|
// newObject.Hours = newDtObject.Hours;
|
|
|
|
// if (LastEntry != null)
|
|
// {
|
|
// newObject.LastEntryDate = LastEntry.EntryDate;
|
|
// newObject.LastCurrencyBalance = LastEntry.CurrencyBalance;
|
|
// newObject.LastHoursBalance = LastEntry.HoursBalance;
|
|
// newObject.LastIncidentsBalance = LastEntry.IncidentsBalance;
|
|
// newObject.HoursBalance = LastEntry.HoursBalance + newObject.Hours;
|
|
// newObject.IncidentsBalance = LastEntry.IncidentsBalance + newObject.Incidents;
|
|
// newObject.CurrencyBalance = LastEntry.CurrencyBalance + newObject.Currency;
|
|
// }
|
|
// else
|
|
// {
|
|
// newObject.HoursBalance = newObject.Hours;
|
|
// newObject.IncidentsBalance = newObject.Incidents;
|
|
// newObject.CurrencyBalance = newObject.Currency;
|
|
// }
|
|
|
|
// await ValidateAsync(newObject);
|
|
// if (HasErrors)
|
|
// return null;
|
|
// else
|
|
// {
|
|
// await ct.ServiceBank.AddAsync(newObject);
|
|
// await ct.SaveChangesAsync();
|
|
// await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);
|
|
// await SearchIndexAsync(newObject, true);
|
|
// await transaction.CommitAsync();
|
|
// await HandlePotentialNotificationEvent(AyaEvent.Created, newObject);
|
|
// return newObject;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// //version for v8 migration purposes only
|
|
// internal async Task<ServiceBank> CreateAsync(ServiceBank newObject)
|
|
// {
|
|
// using (var transaction = await ct.Database.BeginTransactionAsync())
|
|
// {
|
|
// await ValidateAsync(newObject);
|
|
// if (HasErrors)
|
|
// return null;
|
|
// else
|
|
// {
|
|
// await ct.ServiceBank.AddAsync(newObject);
|
|
// await ct.SaveChangesAsync();
|
|
// await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);
|
|
// await SearchIndexAsync(newObject, true);
|
|
// await transaction.CommitAsync();
|
|
// await HandlePotentialNotificationEvent(AyaEvent.Created, newObject);
|
|
// return newObject;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //GET
|
|
// //
|
|
// internal async Task<ServiceBank> GetAsync(long id, bool logTheGetEvent = true)
|
|
// {
|
|
// var ret = await ct.ServiceBank.AsNoTracking().SingleOrDefaultAsync(m => m.Id == id);
|
|
// if (logTheGetEvent && ret != null)
|
|
// await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, BizType, AyaEvent.Retrieved), ct);
|
|
// return ret;
|
|
// }
|
|
|
|
// // ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// // //GET LAST
|
|
// // //
|
|
// // internal async Task<ServiceBank> GetLastForObjectAsync(AyaType aType, long objectId)
|
|
// // {
|
|
|
|
// // var ret = await ct.ServiceBank.OrderByDescending(m => m.EntryDate).SingleOrDefaultAsync(m => m.ObjectId == objectId && m.AType == aType);
|
|
|
|
// // return ret;
|
|
// // }
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //SEARCH
|
|
// //
|
|
// private async Task SearchIndexAsync(ServiceBank obj, bool isNew)
|
|
// {
|
|
// var SearchParams = new Search.SearchIndexProcessObjectParameters(UserTranslationId, obj.Id, BizType);
|
|
// DigestSearchText(obj, SearchParams);
|
|
// if (isNew)
|
|
// await Search.ProcessNewObjectKeywordsAsync(SearchParams);
|
|
// else
|
|
// await Search.ProcessUpdatedObjectKeywordsAsync(SearchParams);
|
|
// }
|
|
|
|
// public async Task<Search.SearchIndexProcessObjectParameters> GetSearchResultSummary(long id, AyaType specificType)
|
|
// {
|
|
// var obj = await GetAsync(id,false);
|
|
// var SearchParams = new Search.SearchIndexProcessObjectParameters();
|
|
// DigestSearchText(obj, SearchParams);
|
|
// return SearchParams;
|
|
// }
|
|
|
|
// public void DigestSearchText(ServiceBank obj, Search.SearchIndexProcessObjectParameters searchParams)
|
|
// {
|
|
// if (obj != null)
|
|
// searchParams.AddText(obj.Name);
|
|
// }
|
|
|
|
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //VALIDATION
|
|
// //
|
|
|
|
// private async Task ValidateAsync(ServiceBank proposedObj)
|
|
// {
|
|
|
|
// //Name required
|
|
// if (string.IsNullOrWhiteSpace(proposedObj.Name))
|
|
// {
|
|
// AddError(ApiErrorCode.VALIDATION_REQUIRED, "Name");
|
|
// return;
|
|
// }
|
|
|
|
|
|
// //Object exists?
|
|
// if (!await BizObjectExistsInDatabase.ExistsAsync(proposedObj.AType, proposedObj.ObjectId, ct))
|
|
// {
|
|
// AddError(ApiErrorCode.NOT_FOUND, "generalerror", $"Bankable source object specified doesn't exist [type:{proposedObj.AType}, id:{proposedObj.ObjectId}]");
|
|
// return;
|
|
// }
|
|
// /*
|
|
// "CONSTRAINT UNQ_ServiceBank UNIQUE (entrydate, objectid, aType, incidentsbalance, hoursbalance, currencybalance), " +
|
|
// "CONSTRAINT UNQ_ServiceBank_Previous_values UNIQUE (lastentrydate, objectid, aType, lastincidentsbalance, lasthoursbalance, lastcurrencybalance), " +
|
|
// "CONSTRAINT fk_ServiceBank_self FOREIGN KEY (lastentrydate, objectid, aType, lastincidentsbalance, lasthoursbalance, lastcurrencybalance) references aservicebank(entrydate, objectid, aType, incidentsbalance, hoursbalance, currencybalance), " +
|
|
// "CONSTRAINT CHK_Servicebank_Valid_IncidentBalance CHECK(incidentsbalance = COALESCE(lastincidentsbalance, 0) + incidents), " +
|
|
// "CONSTRAINT CHK_Servicebank_Valid_CurrencyBalance CHECK(currencybalance = COALESCE(lastcurrencybalance, 0) + currency), " +
|
|
// "CONSTRAINT CHK_Servicebank_Valid_HoursBalance CHECK(hoursbalance = COALESCE(lasthoursbalance, 0) + hours), " +
|
|
// "CONSTRAINT CHK_ServiceBank_Valid_Dates_Sequence CHECK(lastentrydate < entrydate), " +
|
|
// "CONSTRAINT CHK_ServiceBank_Valid_Previous_Columns CHECK((lastentrydate IS NULL AND lastincidentsbalance IS NULL AND lastcurrencybalance IS NULL AND lasthoursbalance IS NULL) OR (lastentrydate IS NOT NULL AND lastincidentsbalance IS NOT NULL AND lastcurrencybalance IS NOT NULL AND lasthoursbalance IS NOT NULL)) "+
|
|
// */
|
|
|
|
// //New entry must have *something* to bank
|
|
// if (proposedObj.Incidents == 0 && proposedObj.Hours == 0 && proposedObj.Currency == 0)
|
|
// {
|
|
// AddError(ApiErrorCode.INVALID_OPERATION, null, "Nothing to bank");
|
|
// return;
|
|
// }
|
|
|
|
// //values must add up
|
|
// if (proposedObj.IncidentsBalance != (proposedObj.Incidents + (proposedObj.LastIncidentsBalance ?? 0)))
|
|
// {
|
|
// AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "generalerror", await Translate("ServiceBankIncidentsBalance"));
|
|
// return;
|
|
// }
|
|
// if (proposedObj.CurrencyBalance != (proposedObj.Currency + (proposedObj.LastCurrencyBalance ?? 0)))
|
|
// {
|
|
// AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "generalerror", await Translate("ServiceBankCurrencyBalance"));
|
|
// return;
|
|
// }
|
|
// if (proposedObj.HoursBalance != (proposedObj.Hours + (proposedObj.LastHoursBalance ?? 0)))
|
|
// {
|
|
// AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "generalerror", await Translate("ServiceBankHoursBalance"));
|
|
// 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.LastCurrencyBalance == null
|
|
// && proposedObj.LastHoursBalance == null
|
|
// && proposedObj.LastIncidentsBalance == null) ||
|
|
// (proposedObj.LastEntryDate != null
|
|
// && proposedObj.LastCurrencyBalance != null
|
|
// && proposedObj.LastHoursBalance != null
|
|
// && proposedObj.LastIncidentsBalance != null)
|
|
// ))
|
|
// {
|
|
// AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "generalerror", "Last* entries must be all empty (opening entry) or none of them empty (any later entry)");
|
|
// return;
|
|
// }
|
|
|
|
|
|
|
|
// //Any form customizations to validate?
|
|
// var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(x => x.FormKey == AyaType.ServiceBank.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);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// //REPORTING
|
|
// //
|
|
// public async Task<JArray> GetReportData(DataListSelectedRequest dataListSelectedRequest, Guid jobId)
|
|
// {
|
|
// JArray ReportData = new JArray();
|
|
// while (idList.Any())
|
|
// {
|
|
// var batch = idList.Take(IReportAbleObject.REPORT_DATA_BATCH_SIZE);
|
|
// idList = idList.Skip(IReportAbleObject.REPORT_DATA_BATCH_SIZE).ToArray();
|
|
// //query for this batch, comes back in db natural order unfortunately
|
|
// var batchResults = await ct.ServiceBank.Where(z => batch.Contains(z.Id)).ToArrayAsync();
|
|
// //order the results back into original
|
|
// var orderedList = from id in batch join z in batchResults on id equals z.Id select z;
|
|
// foreach (ServiceBank w in orderedList)
|
|
// {
|
|
// if (DateTime.UtcNow > renderTimeOutExpiry)
|
|
// throw new ReportRenderTimeOutException();
|
|
// var jo = JObject.FromObject(w);
|
|
// if (!JsonUtil.JTokenIsNullOrEmpty(jo["CustomFields"]))
|
|
// jo["CustomFields"] = JObject.Parse((string)jo["CustomFields"]);
|
|
// ReportData.Add(jo);
|
|
// }
|
|
// }
|
|
// return ReportData;
|
|
// }
|
|
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// // IMPORT EXPORT
|
|
// //
|
|
|
|
// public async Task<JArray> GetExportData(DataListSelectedRequest dataListSelectedRequest, Guid jobId)
|
|
// {
|
|
// //for now just re-use the report data code
|
|
// //this may turn out to be the pattern for most biz object types but keeping it seperate allows for custom usage from time to time
|
|
// return await GetReportData(dataListSelectedRequest, jobId);
|
|
// }
|
|
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// // NOTIFICATION PROCESSING
|
|
// //
|
|
// public async Task HandlePotentialNotificationEvent(AyaEvent ayaEvent, ICoreBizObjectModel proposedObj, ICoreBizObjectModel currentObj = null)
|
|
// {
|
|
// ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger<ServiceBankBiz>();
|
|
// if(ServerBootConfig.SEEDING || ServerBootConfig.MIGRATING) return;
|
|
// log.LogDebug($"HandlePotentialNotificationEvent processing: [AyaType:{this.BizType}, AyaEvent:{ayaEvent}]");
|
|
|
|
// bool isNew = currentObj == null;
|
|
|
|
|
|
// //STANDARD EVENTS FOR ALL OBJECTS
|
|
// await NotifyEventHelper.ProcessStandardObjectEvents(ayaEvent, proposedObj, ct);
|
|
|
|
// //SPECIFIC EVENTS FOR THIS OBJECT
|
|
// var o = (ServiceBank)proposedObj;
|
|
|
|
|
|
// //SERVICE BANK DEPLETED
|
|
// {
|
|
// var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.ServiceBankDepleted).ToListAsync();
|
|
// string SourceName = string.Empty;
|
|
// if (subs.Count > 0)
|
|
// SourceName = BizObjectNameFetcherDirect.Name(o.AType, o.ObjectId, ct);
|
|
|
|
// foreach (var sub in subs)
|
|
// {
|
|
// //not for inactive users
|
|
// if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
|
|
|
// //Has any of the balances changed and is that changed balance within this users selected threshold?
|
|
// //decvalue here refers to the balance left
|
|
// if (
|
|
// (o.LastCurrencyBalance != null && o.CurrencyBalance != o.LastCurrencyBalance && o.CurrencyBalance <= sub.DecValue)
|
|
// || (o.LastHoursBalance != null && o.HoursBalance != o.LastHoursBalance && o.HoursBalance <= sub.DecValue)
|
|
// || (o.LastIncidentsBalance != null && o.IncidentsBalance != o.LastIncidentsBalance && o.IncidentsBalance <= sub.DecValue)
|
|
// )
|
|
// {
|
|
|
|
// NotifyEvent n = new NotifyEvent()
|
|
// {
|
|
// EventType = NotifyEventType.ServiceBankDepleted,
|
|
// UserId = sub.UserId,
|
|
// AyaType = o.AType,
|
|
// ObjectId = o.ObjectId,
|
|
// NotifySubscriptionId = sub.Id,
|
|
// Name = SourceName
|
|
// };
|
|
// await ct.NotifyEvent.AddAsync(n);
|
|
// log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
|
// await ct.SaveChangesAsync();
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// }//end of process notifications
|
|
|
|
|
|
|
|
|
|
// /////////////////////////////////////////////////////////////////////
|
|
|
|
// }//eoc
|
|
|
|
|
|
// }//eons
|
|
|