This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user