From 96ad139e79d42c2fbbcb7baab34ef64eeb064d79 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Wed, 12 May 2021 17:35:43 +0000 Subject: [PATCH] --- server/AyaNova/biz/WorkOrderBiz.cs | 146 ++++++++++++-------- server/AyaNova/models/WorkOrderItemLabor.cs | 2 +- 2 files changed, 93 insertions(+), 55 deletions(-) diff --git a/server/AyaNova/biz/WorkOrderBiz.cs b/server/AyaNova/biz/WorkOrderBiz.cs index df27ddf0..0188fb20 100644 --- a/server/AyaNova/biz/WorkOrderBiz.cs +++ b/server/AyaNova/biz/WorkOrderBiz.cs @@ -1718,70 +1718,98 @@ namespace AyaNova.Biz //////////////////////////////////////////////////////////////////////////////////////////////// //BIZ ACTIONS + // + //automatic actions on record change, called AFTER validation + // also called when contract changes // - private async Task LaborBizActionsAsync(AyaEvent ayaEvent, WorkOrderItemLabor newObj, WorkOrderItemLabor oldObj, IDbContextTransaction transaction) + private async Task LaborBizActionsAsync(AyaEvent ayaEvent, WorkOrderItemLabor newObj, WorkOrderItemLabor oldObj, IDbContextTransaction transaction, bool contractChanged=false) { + //currently no processing required except for created or modified at this time + if (ayaEvent != AyaEvent.Created && ayaEvent != AyaEvent.Modified) + return; + + //SET COST / TAX / PRICE - //automatic actions on record change, called AFTER validation var Contract = await GetCurrentWorkOrderContractFromRelatedAsync(AyaType.WorkOrderItem, newObj.WorkOrderItemId); - switch (ayaEvent) - { - case AyaEvent.Created: - //Tax code - if (newObj.TaxCodeSaleId != null) + //by default apply all automatic actions with further restrictions possible below + bool ApplyTax = true; + bool ApplyListPricing = true; + bool ApplyContractPrice = true; + + //NOTE: If contract itself was changed, that will trigger this from the header change and forceFullUpdate will be in effect + + //if modifed, see what has changed and should be re-applied + if (ayaEvent == AyaEvent.Modified) + { + //If it was a service rate change it's like a new record and list pricing and contract applies + //so only potentially restrict what applies if that hasn't changed + if (newObj.ServiceRateId == oldObj.ServiceRateId) + { + if (newObj.Price != oldObj.Price)//user manually overrode the price { - - 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; - } - else - { - newObj.TaxAPct = 0; - newObj.TaxBPct = 0; - newObj.TaxOnTax = false; - } + ApplyListPricing = false; + ApplyContractPrice = false; } + } - //Pricing - if (newObj.ServiceRateId != null) - { - var s = await ct.ServiceRate.AsNoTracking().FirstOrDefaultAsync(z => z.Id == newObj.ServiceRateId); - if (s != null) - { - newObj.Cost = s.Cost; - newObj.ListPrice = s.Charge; - } - else - { - newObj.Cost = 0; - newObj.ListPrice = 0; - } - } - - //Contract - if (Contract != null) - { - //update discount pricing - if (Contract.ServiceRatesOverridePct != 0) - { - if (Contract.ServiceRatesOverrideType == ContractOverrideType.CostMarkup) - newObj.Price = newObj.Cost + (newObj.Cost * Contract.ServiceRatesOverridePct); - else if (Contract.ServiceRatesOverrideType == ContractOverrideType.PriceDiscount) - newObj.Price = newObj.ListPrice - (newObj.ListPrice * Contract.ServiceRatesOverridePct); - } - } - break; - case AyaEvent.Modified: - - break; + //same taxes + if (newObj.TaxCodeSaleId == oldObj.TaxCodeSaleId) + ApplyTax = false; } + //Tax code + if (ApplyTax && 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; + } + else + { + newObj.TaxAPct = 0; + newObj.TaxBPct = 0; + newObj.TaxOnTax = false; + } + } + + //Pricing + if (ApplyListPricing && newObj.ServiceRateId != null) + { + var s = await ct.ServiceRate.AsNoTracking().FirstOrDefaultAsync(z => z.Id == newObj.ServiceRateId); + if (s != null) + { + newObj.Cost = s.Cost; + newObj.ListPrice = s.Charge; + } + else + { + newObj.Cost = 0; + newObj.ListPrice = 0; + } + } + + //Contract + if (ApplyContractPrice && Contract != null) + { + //update discount pricing + if (Contract.ServiceRatesOverridePct != 0) + { + if (Contract.ServiceRatesOverrideType == ContractOverrideType.CostMarkup) + newObj.Price = newObj.Cost + (newObj.Cost * Contract.ServiceRatesOverridePct); + else if (Contract.ServiceRatesOverrideType == ContractOverrideType.PriceDiscount) + newObj.Price = newObj.ListPrice - (newObj.ListPrice * Contract.ServiceRatesOverridePct); + } + } + + + + } @@ -4090,10 +4118,20 @@ namespace AyaNova.Biz //////////////////////////////////////////////////////////////////////////////////////////////// //GET CONTRACT FOR WORKORDER FROM RELATIVE // + + //cache the contract to save repeatedly fetching it for this operation + internal Contract mContractInEffect = null; + internal bool mFetchedContractAlready = false;//null contract isn't enough to know it was fetched as it could just not have a contract so this is required + internal async Task GetCurrentWorkOrderContractFromRelatedAsync(AyaType ayaType, long id) { //instantiated method to save adding the context - return await GetCurrentWorkOrderContractFromRelatedAsync(ayaType, id, ct); + if (mFetchedContractAlready == false) + { + mContractInEffect = await GetCurrentWorkOrderContractFromRelatedAsync(ayaType, id, ct); + mFetchedContractAlready = true; + } + return mContractInEffect; } internal static async Task GetCurrentWorkOrderContractFromRelatedAsync(AyaType ayaType, long id, AyContext ct) { diff --git a/server/AyaNova/models/WorkOrderItemLabor.cs b/server/AyaNova/models/WorkOrderItemLabor.cs index 4693caa9..82c7e791 100644 --- a/server/AyaNova/models/WorkOrderItemLabor.cs +++ b/server/AyaNova/models/WorkOrderItemLabor.cs @@ -33,7 +33,7 @@ namespace AyaNova.Models //from case 3748 - Cost, this is the entered Cost for the item at time of selection - ListPrice, [REQUIRED] this is the un-discounted per unit price of the item be it labor, parts, loaner, travel etc. What is normally charged at that moment in time for this item if it wasn't discounted. - - Price, [NULLABLE] this is the EFFECTIVE PRICE either contract determined price calculated from ListPrice, otherwise it's a copy of the list price. User with sufficient rights can can override it to enter a different amount which effectively supports manual discount feature in v7 which was by %. This is the *actual* price used in calculations. + - Price, [NULLABLE] this is the EFFECTIVE PER UNIT PRICE either contract determined price calculated from ListPrice, otherwise it's a copy of the list price. User with sufficient rights can can override it to enter a different amount which effectively supports manual discount feature in v7 which was by %. This is the *actual* price used in calculations. - TaxName copied from selected tax code, not directly editable - TaxAPct copied from selected tax code, not directly editable - TaxBPct copied from selected tax code, not directly editable