diff --git a/docs/8.0/ayanova/docs/svc-workorders.md b/docs/8.0/ayanova/docs/svc-workorders.md index 73986f65..4ac8959e 100644 --- a/docs/8.0/ayanova/docs/svc-workorders.md +++ b/docs/8.0/ayanova/docs/svc-workorders.md @@ -53,7 +53,7 @@ docs / sections required * All restrictions listed above in Work order *Item* restrictions plus: * All work order header fields visible but not editable other than work order status which has a separately configurable role restriction setting (including attachments, wiki and tags) * Form main menu items available: none except for Report which has a separately configurable role restriction setting - * Tasks: view and edit existing tasks only, no add or remove or changing task text + * Tasks: view and edit existing tasks, set completion type and date only, no add or remove or changing other fields * Scheduled Users: view only where they are the selected User and convert to labor record * Labors: add (no user selection defaults to themselves), remove, view and edit only when they are the selected User * Travels: add (no user selection defaults to themselves), remove, view and edit only when they are the selected User @@ -68,7 +68,7 @@ docs / sections required * All restrictions listed above in Work order *Item* restrictions plus: * No work order header fields visible except for Customer name and service address * Form main menu items available: none except for Report which has a separately configurable role restriction setting - * Tasks: view and edit existing tasks only, no add or remove or changing task text + * Tasks: view and edit existing tasks, set completion type and date only, no add or remove or changing other fields * Scheduled Users: view only where they are the selected User and convert to labor record * Labors: add (no user selection defaults to themselves), remove, view and edit only when they are the selected User * Travels: add (no user selection defaults to themselves), remove, view and edit only when they are the selected User @@ -83,7 +83,7 @@ docs / sections required * All restrictions listed above in Work order *Item* restrictions plus: * No work order header fields visible except for Customer name * Form main menu items available: none except for Report which has a separately configurable role restriction setting - * Tasks: view and edit existing tasks only, no add or remove or changing task text + * Tasks: view and edit existing tasks, set completion type and date only, no add or remove or changing other fields * Scheduled Users: view only where they are the selected User and convert to labor record * Labors: add (no user selection defaults to themselves), remove, view and edit only when they are the selected User * Travels: add (no user selection defaults to themselves), remove, view and edit only when they are the selected User diff --git a/server/AyaNova/biz/WorkOrderBiz.cs b/server/AyaNova/biz/WorkOrderBiz.cs index dead1e60..a016ee51 100644 --- a/server/AyaNova/biz/WorkOrderBiz.cs +++ b/server/AyaNova/biz/WorkOrderBiz.cs @@ -2983,136 +2983,6 @@ namespace AyaNova.Biz } - // //////////////////////////////////////////////////////////////////////////////////////////////// - // //BIZ ACTIONS - // // - // // - // private async Task LaborBizActionsAsync(AyaEvent ayaEvent, WorkOrderItemLabor newObj, WorkOrderItemLabor oldObj, IDbContextTransaction transaction) - // { - // //automatic actions on record change, called AFTER validation - - // //currently no processing required except for created or modified at this time - // if (ayaEvent != AyaEvent.Created && ayaEvent != AyaEvent.Modified) - // return; - - // //SET TAXES AND PRICING - - // //by default apply all automatic actions with further restrictions possible below - // bool ApplyTax = true; - // bool SetPrice = true; - - // //if modifed, see what has changed and should be re-applied - // if (ayaEvent == AyaEvent.Modified) - // { - // //If it wasn't a service rate or quantity change there is no need to set pricing - // if (newObj.ServiceRateId == oldObj.ServiceRateId && newObj.ServiceRateQuantity == oldObj.ServiceRateQuantity) - // { - // SetPrice = false; - // } - // //If taxes haven't change then no need to update taxes - // if (newObj.TaxCodeSaleId == oldObj.TaxCodeSaleId) - // ApplyTax = false; - // } - - // //Tax code - // if (ApplyTax) - // { - // //Default in case nothing to apply - // newObj.TaxAPct = 0; - // newObj.TaxBPct = 0; - // newObj.TaxOnTax = false; - // newObj.TaxName = ""; - - // if (newObj.TaxCodeSaleId != null) - // { - // var t = await ct.TaxCode.AsNoTracking().FirstOrDefaultAsync(z => z.Id == newObj.TaxCodeSaleId); - // if (t != null) - // { - // newObj.TaxAPct = t.TaxAPct; - // newObj.TaxBPct = t.TaxBPct; - // newObj.TaxOnTax = t.TaxOnTax; - // newObj.TaxName = t.Name; - // } - // } - // } - - // //Pricing - // if (SetPrice) - // { - // var Contract = await GetCurrentWorkOrderContractFromRelatedAsync(AyaType.WorkOrderItem, newObj.WorkOrderItemId); - // await LaborSetPrice(newObj, Contract); - - - // } - // } - - // //////////////////////////////////////////////////////////////////////////////////////////////// - // // SET PER UNIT LIST PRICE - // // - // //(called by woitemlabor save and also by header save on change of contract) - // private async Task LaborSetPrice(WorkOrderItemLabor o, Contract c) - // { - // //default in case nothing to apply - // o.Cost = 0; - // o.ListPrice = 0; - // o.Price = 0; - - // //in v7 it was ok to have no service rate selected - // //not sure why but carried forward to v8 so.. - // if (o.ServiceRateId == null) - // return; - - // var Rate = await ct.ServiceRate.AsNoTracking().FirstOrDefaultAsync(z => z.Id == o.ServiceRateId); - // if (Rate == null) - // { - // AddError(ApiErrorCode.NOT_FOUND, "generalerror", "Service rate not found");//this should never happen, no point in localizing - // return; - // } - - // o.Cost = Rate.Cost; - // o.ListPrice = Rate.Charge; - // o.Price = o.ListPrice;//default is list price unless a contract overrides it - - // if (c == null) - // return;//No contract so bail out now, it's done - - - // //POTENTIAL CONTRACT ADJUSTMENTS - // //First check if there is a matching tagged service rate contract discount, that takes precedence - // if (c.ContractServiceRateOverrideItems.Count > 0) - // { - // //Iterate all contract tagged items in order of ones with the most tags first - // foreach (var csr in c.ContractServiceRateOverrideItems.OrderByDescending(z => z.Tags.Count)) - // if (csr.Tags.All(z => Rate.Tags.Any(x => x == z))) - // { - // if (csr.OverridePct != 0) - // { - // var pct = csr.OverridePct / 100; - // //found a match, apply the discount and return - // if (csr.OverrideType == ContractOverrideType.CostMarkup) - // o.Price = o.Cost + (o.Cost * pct); - // else if (csr.OverrideType == ContractOverrideType.PriceDiscount) - // o.Price = o.ListPrice - (o.ListPrice * pct); - // return; - // } - // } - // } - - // //No tag discounts, so check for a generic one - // if (c.ServiceRatesOverridePct == 0) - // return;// no generic discount for all items so bail now - - // { - // var pct = c.ServiceRatesOverridePct / 100; - - // //Contract has a generic override so apply it - // if (c.ServiceRatesOverrideType == ContractOverrideType.CostMarkup) - // o.Price = o.Cost + (o.Cost * pct); - // else if (c.ServiceRatesOverrideType == ContractOverrideType.PriceDiscount) - // o.Price = o.ListPrice - (o.ListPrice * pct); - // } - - // } //////////////////////////////////////////////////////////////////////////////////////////////// @@ -3147,7 +3017,13 @@ namespace AyaNova.Biz AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "generalerror", await Translate("WorkOrderErrorLocked")); return;//this is a completely disqualifying error } + } + if (UserIsRestrictedType + { + //Scheduled Users: view only where they are the selected User and convert to labor record + AddError(ApiErrorCode.NOT_AUTHORIZED, "generalerror"); + return; } //Start date AND end date must both be null or both contain values @@ -5099,12 +4975,12 @@ namespace AyaNova.Biz return;//this is a completely disqualifying error } - // //TEST TEST TEST - // if (proposedObj.EstimatedQuantity == 69) - // { - // AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, $"EstimatedQuantity", "◈◈ TEST SAVE ERROR ◈◈"); - // } - + if (UserIsRestrictedType) + { + //Scheduled Users: view only where they are the selected User and convert to labor record + AddError(ApiErrorCode.NOT_AUTHORIZED, "generalerror"); + return; + } //Check state if updatable right now if (!isNew) @@ -5180,12 +5056,12 @@ namespace AyaNova.Biz return; } - // //TEST TEST TEST - // if (obj.EstimatedQuantity == 69) - // { - // AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, $"EstimatedQuantity", "◈◈ TEST DELETE ERROR ◈◈"); - // } - + if (UserIsRestrictedType) + { + //Scheduled Users: view only where they are the selected User and convert to labor record + AddError(ApiErrorCode.NOT_AUTHORIZED, "generalerror"); + return; + } //re-check rights here necessary due to traversal delete from Principle object if (!Authorized.HasDeleteRole(CurrentUserRoles, AyaType.WorkOrderItemScheduledUser)) { @@ -5527,6 +5403,8 @@ namespace AyaNova.Biz AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "WorkOrderItemId"); return;//this is a completely disqualifying error } + + //Check state if updatable right now if (!isNew) { @@ -5540,12 +5418,26 @@ namespace AyaNova.Biz } } + if (isNew && UserIsRestrictedType) + { + //restricted users are not allowed to make new task entries only fill them out + AddError(ApiErrorCode.NOT_AUTHORIZED, "generalerror"); + return; + } + + if (!isNew && UserIsRestrictedType) + { + //* Tasks: view and edit existing tasks, set completion type and date only, no add or remove or changing other fields + //note that UI will prevent this, this rule is only backup for 3rd party api users + if (currentObj.Task != proposedObj.Task) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "Task"); + if (currentObj.CompletedByUserId != UserId) AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "CompletedByUserId"); + if (currentObj.Sequence != proposedObj.Sequence) AddError(ApiErrorCode.VALIDATION_NOT_CHANGEABLE, "Sequence"); + } + if (string.IsNullOrWhiteSpace(proposedObj.Task)) AddError(ApiErrorCode.VALIDATION_REQUIRED, "Task"); - //TEST TEST TEST ERROR - if (proposedObj.Sequence == 999) - AddError(ApiErrorCode.VALIDATION_INVALID_VALUE, "Sequence"); + //Any form customizations to validate? var FormCustomization = await ct.FormCustom.AsNoTracking().SingleOrDefaultAsync(z => z.FormKey == AyaType.WorkOrderItemTask.ToString()); @@ -5570,6 +5462,13 @@ namespace AyaNova.Biz return; } + if (UserIsRestrictedType) + { + //restricted users are not allowed to delete a task only fill them out + AddError(ApiErrorCode.NOT_AUTHORIZED, "generalerror"); + return; + } + //re-check rights here necessary due to traversal delete from Principle object if (!Authorized.HasDeleteRole(CurrentUserRoles, AyaType.WorkOrderItemTask)) {