This commit is contained in:
2021-07-16 17:46:50 +00:00
parent c53e1b07fd
commit dc280f41cd

View File

@@ -169,96 +169,47 @@ namespace AyaNova.Biz
}
}
// ////////////////////////////////////////////////////////////////////////////////////////////////
// //DUPLICATE
// //
// internal async Task<WorkOrder> WorkOrderDuplicateAsync(long id)
// {
// WorkOrder dbObject = await WorkOrderGetAsync(id, false);
// if (dbObject == null)
// {
// AddError(ApiErrorCode.NOT_FOUND, "id");
// return null;
// }
// WorkOrder newObject = new WorkOrder();
// CopyObject.Copy(dbObject, newObject, "Wiki, Serial, States");
// //walk the tree and reset all id's and concurrencies
// //TOP
// newObject.Id = 0;
// newObject.Concurrency = 0;
// foreach (var o in newObject.Items)
// {
// o.Id = 0;
// o.Concurrency = 0;
// foreach (var v in o.Expenses)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.Labors)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.Loans)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.OutsideServices)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.PartRequests)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.Parts)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.ScheduledUsers)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.Tasks)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.Travels)
// { v.Id = 0; v.Concurrency = 0; }
// foreach (var v in o.Units)
// { v.Id = 0; v.Concurrency = 0; }
// }
// await ct.WorkOrder.AddAsync(newObject);
// await ct.SaveChangesAsync();
// await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, newObject.Id, BizType, AyaEvent.Created), ct);
// await WorkOrderSearchIndexAsync(newObject, true);
// await TagBiz.ProcessUpdateTagsInRepositoryAsync(ct, newObject.Tags, null);
// await WorkOrderPopulateVizFields(newObject, false);//doing this here ahead of notification because notification may require the viz field lookup anyway and afaict no harm in it
// await WorkOrderHandlePotentialNotificationEvent(AyaEvent.Created, newObject);
// return newObject;
// }
//workorder needs to be fetched internally from several places for rule checking etc
//this just gets it raw and lets others process
private async Task<WorkOrder> WorkOrderGetFullAsync(long id)
{
//https://docs.microsoft.com/en-us/ef/core/querying/related-data
//docs say this will not query twice but will recognize the duplicate woitem bit which is required for multiple grandchild collections
return await ct.WorkOrder.AsSplitQuery().AsNoTracking()
.Include(s => s.States)
.Include(w => w.Items.OrderBy(item => item.Sequence))
.ThenInclude(wi => wi.Expenses)
.Include(w => w.Items)
.ThenInclude(wi => wi.Labors)
.Include(w => w.Items)
.ThenInclude(wi => wi.Loans)
.Include(w => w.Items)
.ThenInclude(wi => wi.Parts)
.Include(w => w.Items)
.ThenInclude(wi => wi.PartRequests)
.Include(w => w.Items)
.ThenInclude(wi => wi.ScheduledUsers)
.Include(w => w.Items)
.ThenInclude(wi => wi.Tasks.OrderBy(t => t.Sequence))
.Include(w => w.Items)
.ThenInclude(wi => wi.Travels)
.Include(w => w.Items)
.ThenInclude(wi => wi.Units)
.Include(w => w.Items)
.ThenInclude(wi => wi.OutsideServices)
.SingleOrDefaultAsync(z => z.Id == id);
}
////////////////////////////////////////////////////////////////////////////////////////////////
// GET
//
internal async Task<WorkOrder> WorkOrderGetAsync(long id, bool populateDisplayFields, bool logTheGetEvent = true)
{
//Note: there could be rules checking here in future, i.e. can only get own workorder or something
//if so, then need to implement AddError and in route handle Null return with Error check just like PUT route does now
//https://docs.microsoft.com/en-us/ef/core/querying/related-data
//docs say this will not query twice but will recognize the duplicate woitem bit which is required for multiple grandchild collections
var ret =
await ct.WorkOrder.AsSplitQuery().AsNoTracking()
.Include(s => s.States)
.Include(w => w.Items.OrderBy(item => item.Sequence))
.ThenInclude(wi => wi.Expenses)
.Include(w => w.Items)
.ThenInclude(wi => wi.Labors)
.Include(w => w.Items)
.ThenInclude(wi => wi.Loans)
.Include(w => w.Items)
.ThenInclude(wi => wi.Parts)
.Include(w => w.Items)
.ThenInclude(wi => wi.PartRequests)
.Include(w => w.Items)
.ThenInclude(wi => wi.ScheduledUsers)
.Include(w => w.Items)
.ThenInclude(wi => wi.Tasks.OrderBy(t => t.Sequence))
.Include(w => w.Items)
.ThenInclude(wi => wi.Travels)
.Include(w => w.Items)
.ThenInclude(wi => wi.Units)
.Include(w => w.Items)
.ThenInclude(wi => wi.OutsideServices)
.SingleOrDefaultAsync(z => z.Id == id);
var ret = await WorkOrderGetFullAsync(id);
if (ret != null)
{
@@ -2652,7 +2603,7 @@ namespace AyaNova.Biz
uid: Date.now() //used for
*/
if (proposedObj.ChargeAmount != 0) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "ChargeAmount");
// if (proposedObj.TaxPaid != 0) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "TaxPaid");
// if (proposedObj.TaxPaid != 0) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "TaxPaid");
if (proposedObj.ChargeTaxCodeId != null) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "ChargeTaxCodeId");
if (proposedObj.ReimburseUser != false) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "ReimburseUser");
if (proposedObj.ChargeToCustomer != false) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "ChargeToCustomer");
@@ -6007,6 +5958,10 @@ namespace AyaNova.Biz
*/
#region WorkOrderItemUnit level
//this is set by validation for further processing later if applicable
private Contract currentUnitContract = null;
////////////////////////////////////////////////////////////////////////////////////////////////
//EXISTS
internal async Task<bool> UnitExistsAsync(long id)
@@ -6019,6 +5974,10 @@ namespace AyaNova.Biz
//
internal async Task<WorkOrderItemUnit> UnitCreateAsync(WorkOrderItemUnit newObject)
{
//todo: contract stuff and validation of no other existing contracted unit
//assumptions: this create only gets called if there is an existing woheader saved in all cases
await UnitValidateAsync(newObject, null);
if (HasErrors)
return null;
@@ -6184,7 +6143,7 @@ namespace AyaNova.Biz
//TODO: ADD VALIDATIONS:
// - A work order *MUST* have only one Unit with a Contract, if there is already a unit with a contract on this workorder then a new one cannot be added and it will reject with a validation error
// a unit record is saved only *after* there is already a header (by api users and our client software) so can easily check and set here
//run validation and biz rules
bool isNew = currentObj == null;
@@ -6224,6 +6183,35 @@ namespace AyaNova.Biz
//Contracted unit? Only one per work order is allowed
if (isNew || proposedObj.UnitId != currentObj.UnitId)
{
//See if this unit has a contract, if so then see if the contract is active, if so then iterate workorder graph and check all other units for same
//if any found then reject this
var proposedContractInfo = await ct.Unit.AsNoTracking().Where(x => x.Id == proposedObj.Id).Select(x => new { x.ContractExpires, x.ContractId }).FirstOrDefaultAsync();
if (proposedContractInfo.ContractId != null && proposedContractInfo.ContractExpires > DateTime.UtcNow)
{
//added woitemunit has a contract and apparently unexpired so need to check if contract is still active
currentUnitContract = await GetFullyPopulatedContractGraphFromIdAsync(proposedContractInfo.ContractId);
if (currentUnitContract != null && currentUnitContract.Active)
{
//iterate work order and check for other contracted unit
var woId = await GetWorkOrderIdFromRelativeAsync(AyaType.WorkOrderItem, proposedObj.WorkOrderItemId, ct);
var w = await WorkOrderGetFullAsync(woId.WorkOrderId);
//iterate, look for *other* woitemunit records, are they contracted already?
}
else
{
currentUnitContract = null;//just in case it's non active but present so later biz actions don't process it
}
}
//check if there is another contracted unit already on this work order
}
//Any form customizations to validate?
var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.WorkOrderItemUnit.ToString());
@@ -6433,17 +6421,24 @@ namespace AyaNova.Biz
if (id == null) return null;
if (mFetchedContractAlready == false)
{
mContractInEffect = await ct.Contract.AsSplitQuery().AsNoTracking()
.Include(c => c.ServiceRateItems)
.Include(c => c.TravelRateItems)
.Include(c => c.ContractPartOverrideItems)
.Include(c => c.ContractTravelRateOverrideItems)
.Include(c => c.ContractServiceRateOverrideItems)
.FirstOrDefaultAsync(z => z.Id == id);
mContractInEffect = await GetFullyPopulatedContractGraphFromIdAsync(id);
}
return mContractInEffect;
}
internal async Task<Contract> GetFullyPopulatedContractGraphFromIdAsync(long? id)
{
if (id == null) return null;
return await ct.Contract.AsSplitQuery().AsNoTracking()
.Include(c => c.ServiceRateItems)
.Include(c => c.TravelRateItems)
.Include(c => c.ContractPartOverrideItems)
.Include(c => c.ContractTravelRateOverrideItems)
.Include(c => c.ContractServiceRateOverrideItems)
.FirstOrDefaultAsync(z => z.Id == id);
}
////////////////////////////////////////////////////////////////////////////////////////////////
//GET CURRENT STATUS FOR WORKORDER FROM RELATIVE