diff --git a/server/AyaNova/biz/WorkOrderBiz.cs b/server/AyaNova/biz/WorkOrderBiz.cs index 693b4fe4..295016fe 100644 --- a/server/AyaNova/biz/WorkOrderBiz.cs +++ b/server/AyaNova/biz/WorkOrderBiz.cs @@ -2657,7 +2657,75 @@ namespace AyaNova.Biz // o.WorkOrderOverseerViz = await ct.User.AsNoTracking().Where(x => x.Id == o.WorkOrderOverseerId).Select(x => x.Name).FirstOrDefaultAsync(); } + //////////////////////////////////////////////////////////////////////////////////////////////// + //BIZ ACTIONS + // + // + private async Task PartBizActionsAsync(AyaEvent ayaEvent, WorkOrderItemPart newObj, WorkOrderItemPart 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 ApplyPricingUpdate = true; + + //if modifed, see what has changed and should be re-applied + if (ayaEvent == AyaEvent.Modified) + { + //If it wasn't a complete part change there is no need to set pricing + if (newObj.PartId == oldObj.PartId) + { + ApplyPricingUpdate = false; + } + //If taxes haven't change then no need to update taxes + if (newObj.TaxPartSaleId == oldObj.TaxPartSaleId) + ApplyTax = false; + } + + //Tax code + if (ApplyTax) + { + //Default in case nothing to apply + newObj.TaxAPct = 0; + newObj.TaxBPct = 0; + newObj.TaxOnTax = false; + + if (newObj.TaxPartSaleId != null) + { + var t = await ct.TaxCode.AsNoTracking().FirstOrDefaultAsync(z => z.Id == newObj.TaxPartSaleId); + if (t != null) + { + newObj.TaxAPct = t.TaxAPct; + newObj.TaxBPct = t.TaxBPct; + newObj.TaxOnTax = t.TaxOnTax; + } + } + } + + //Pricing + if (ApplyPricingUpdate) + { + //default in case nothing to apply + newObj.Cost = 0; + newObj.ListPrice = 0; + newObj.Price = 0; + + var s = await ct.Part.AsNoTracking().FirstOrDefaultAsync(z => z.Id == newObj.PartId); + if (s != null) + { + newObj.Cost = s.Cost; + newObj.ListPrice = s.Retail; + var Contract = await GetCurrentWorkOrderContractFromRelatedAsync(AyaType.WorkOrderItem, newObj.WorkOrderItemId); + PartSetListPrice(newObj, Contract); + } + } + } //////////////////////////////////////////////////////////////////////////////////////////////// // SET PER UNIT LIST PRICE @@ -3700,6 +3768,81 @@ namespace AyaNova.Biz } + //////////////////////////////////////////////////////////////////////////////////////////////// + //BIZ ACTIONS + // + // + private async Task TravelBizActionsAsync(AyaEvent ayaEvent, WorkOrderItemTravel newObj, WorkOrderItemTravel 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 ApplyPricingUpdate = true; + + //if modifed, see what has changed and should be re-applied + if (ayaEvent == AyaEvent.Modified) + { + //If it wasn't a service rate change there is no need to set pricing + if (newObj.TravelRateId == oldObj.TravelRateId) + { + ApplyPricingUpdate = 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; + + 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; + } + } + } + + //Pricing + if (ApplyPricingUpdate) + { + //default in case nothing to apply + newObj.Cost = 0; + newObj.ListPrice = 0; + newObj.Price = 0; + + //in v7 it was ok to have no service rate selected + //not sure why but carried forward to v8 so.. + if (newObj.TravelRateId != null) + { + var s = await ct.TravelRate.AsNoTracking().FirstOrDefaultAsync(z => z.Id == newObj.TravelRateId); + if (s != null) + { + newObj.Cost = s.Cost; + newObj.ListPrice = s.Charge; + var Contract = await GetCurrentWorkOrderContractFromRelatedAsync(AyaType.WorkOrderItem, newObj.WorkOrderItemId); + TravelSetListPrice(newObj, Contract); + } + } + } + } + //////////////////////////////////////////////////////////////////////////////////////////////// // SET PER UNIT LIST PRICE // diff --git a/server/AyaNova/models/WorkOrderItemPart.cs b/server/AyaNova/models/WorkOrderItemPart.cs index be9e056d..ac6721c9 100644 --- a/server/AyaNova/models/WorkOrderItemPart.cs +++ b/server/AyaNova/models/WorkOrderItemPart.cs @@ -18,13 +18,30 @@ namespace AyaNova.Models [Required] public long PartWarehouseId { get; set; } [Required] - public decimal Quantity { get; set; } - public decimal Cost { get; set; }//cost at time of entry from part table - public decimal BasePrice { get; set; }//part retail price at time of entry (V7 "Price") - public decimal Price { get; set; }//contract adjusted price or a copy of BasePrice if no contract - public decimal ManualDiscountPct { get; set; }// (V7 "Discount") ad-hoc / % off of the contractprice (which is always set regardless if contract or not) entered manually + public decimal Quantity { get; set; } public long? TaxPartSaleId { get; set; } + //PRICE FIELDS + [Required] + public decimal Cost { get; set; } + [Required] + public decimal ListPrice { get; set; } + [Required] + public decimal Price { get; set; } + [Required] + public string TaxName { get; set; } + [Required] + public decimal TaxAPct { get; set; } + [Required] + public decimal TaxBPct { get; set; } + [Required] + public bool TaxOnTax { get; set; } + [NotMapped] + public decimal TaxAViz { get; set; } + [NotMapped] + public decimal TaxBViz { get; set; } + [NotMapped] + public decimal LineTotalViz { get; set; } //UTILITY FIELDS [NotMapped] diff --git a/server/AyaNova/models/WorkOrderItemTravel.cs b/server/AyaNova/models/WorkOrderItemTravel.cs index 57a726b5..44c67497 100644 --- a/server/AyaNova/models/WorkOrderItemTravel.cs +++ b/server/AyaNova/models/WorkOrderItemTravel.cs @@ -10,7 +10,7 @@ namespace AyaNova.Models { public long Id { get; set; } public uint Concurrency { get; set; } - + public long? UserId { get; set; } public DateTime? TravelStartDate { get; set; } public DateTime? TravelStopDate { get; set; } @@ -21,9 +21,34 @@ namespace AyaNova.Models public long? ServiceBankId { get; set; } public long? TaxCodeSaleId { get; set; } public decimal Distance { get; set; } - public decimal BasePrice { get; set; }//Rate price per unit at time of entry - public decimal Price { get; set; }//contract adjusted price or a copy of BasePrice if no contract - public decimal ManualDiscountPct { get; set; }// (V7 "Discount") ad-hoc / % off of the contractprice (which is always set regardless if contract or not) entered manually + + // public decimal BasePrice { get; set; }//Rate price per unit at time of entry + // public decimal Price { get; set; }//contract adjusted price or a copy of BasePrice if no contract + // public decimal ManualDiscountPct { get; set; }// (V7 "Discount") ad-hoc / % off of the contractprice (which is always set regardless if contract or not) entered manually + + //PRICE FIELDS + [Required] + public decimal Cost { get; set; } + [Required] + public decimal ListPrice { get; set; } + [Required] + public decimal Price { get; set; } + [Required] + public string TaxName { get; set; } + [Required] + public decimal TaxAPct { get; set; } + [Required] + public decimal TaxBPct { get; set; } + [Required] + public bool TaxOnTax { get; set; } + [NotMapped] + public decimal TaxAViz { get; set; } + [NotMapped] + public decimal TaxBViz { get; set; } + [NotMapped] + public decimal LineTotalViz { get; set; } + + //UTILITY FIELDS [NotMapped] @@ -36,7 +61,7 @@ namespace AyaNova.Models public WorkOrderItem WorkOrderItem { get; set; } [NotMapped, JsonIgnore] - public AyaType AyaType { get => AyaType.WorkOrderItemTravel; } + public AyaType AyaType { get => AyaType.WorkOrderItemTravel; } }//eoc }//eons diff --git a/server/AyaNova/util/AySchema.cs b/server/AyaNova/util/AySchema.cs index d8bcd7dd..594121c0 100644 --- a/server/AyaNova/util/AySchema.cs +++ b/server/AyaNova/util/AySchema.cs @@ -783,7 +783,7 @@ $BODY$ LANGUAGE PLPGSQL STABLE"); //WORKORDERITEM LABOR await ExecQueryAsync("CREATE TABLE aworkorderitemlabor (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, workorderitemid BIGINT NOT NULL REFERENCES aworkorderitem (id), " + "userid BIGINT REFERENCES auser, servicestartdate TIMESTAMP, servicestopdate TIMESTAMP, servicerateid BIGINT REFERENCES aservicerate, servicedetails text, " - + "serviceratequantity DECIMAL(19,5) NOT NULL default 0, nochargequantity DECIMAL(19,5) NOT NULL default 0, servicebankid BIGINT REFERENCES aservicebank, taxcodesaleid BIGINT REFERENCES ataxcode, " + + "serviceratequantity DECIMAL(19,5) NOT NULL default 0, nochargequantity DECIMAL(19,5) NOT NULL default 0, servicebankid BIGINT REFERENCES aservicebank, taxcodesaleid BIGINT REFERENCES ataxcode, " + "cost DECIMAL(38,18) NOT NULL default 0, listprice DECIMAL(38,18) NOT NULL default 0, price DECIMAL(38,18) NOT NULL default 0, taxapct DECIMAL(8,5) NOT NULL default 0, " + "taxbpct DECIMAL(8,5) NOT NULL default 0, taxontax BOOL NOT NULL default false, taxname TEXT " + ")"); @@ -796,10 +796,10 @@ $BODY$ LANGUAGE PLPGSQL STABLE"); await ExecQueryAsync("ALTER TABLE aloanunit ADD column workorderitemloanid BIGINT NULL REFERENCES aworkorderitemloan"); //WORKORDERITEM PART - await ExecQueryAsync("CREATE TABLE aworkorderitempart (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, workorderitemid BIGINT NOT NULL REFERENCES aworkorderitem (id), " - + "description TEXT, serials TEXT, partid BIGINT NOT NULL REFERENCES apart, partwarehouseid BIGINT NOT NULL REFERENCES apartwarehouse, " - + "quantity DECIMAL(19,5) NOT NULL default 0, cost DECIMAL(38,18) NOT NULL default 0, baseprice DECIMAL(38,18) NOT NULL default 0, price DECIMAL(38,18) NOT NULL default 0, " - + "manualdiscountpct DECIMAL(8,5) NOT NULL default 0, taxpartsaleid BIGINT REFERENCES ataxcode " + await ExecQueryAsync("CREATE TABLE aworkorderitempart (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, workorderitemid BIGINT NOT NULL REFERENCES aworkorderitem (id), description TEXT, serials TEXT, " + + "partid BIGINT NOT NULL REFERENCES apart, partwarehouseid BIGINT NOT NULL REFERENCES apartwarehouse, quantity DECIMAL(19,5) NOT NULL default 0, taxpartsaleid BIGINT REFERENCES ataxcode " + + "cost DECIMAL(38,18) NOT NULL default 0, listprice DECIMAL(38,18) NOT NULL default 0, price DECIMAL(38,18) NOT NULL default 0, taxapct DECIMAL(8,5) NOT NULL default 0, " + + "taxbpct DECIMAL(8,5) NOT NULL default 0, taxontax BOOL NOT NULL default false, taxname TEXT " + ")"); //WORKORDERITEM PART REQUEST @@ -823,8 +823,9 @@ $BODY$ LANGUAGE PLPGSQL STABLE"); await ExecQueryAsync("CREATE TABLE aworkorderitemtravel (id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, workorderitemid BIGINT NOT NULL REFERENCES aworkorderitem (id), " + "userid BIGINT REFERENCES auser, travelstartdate TIMESTAMP, travelstopdate TIMESTAMP, travelrateid BIGINT REFERENCES atravelrate, traveldetails text, " + "travelratequantity DECIMAL(19,5) NOT NULL default 0, nochargequantity DECIMAL(19,5) NOT NULL default 0, servicebankid BIGINT REFERENCES aservicebank, " - + "taxcodesaleid BIGINT REFERENCES ataxcode, distance DECIMAL(19,5) NOT NULL default 0, baseprice DECIMAL(38,18) NOT NULL default 0, price DECIMAL(38,18) NOT NULL default 0, " - + "manualdiscountpct DECIMAL(8,5) NOT NULL default 0 " + + "taxcodesaleid BIGINT REFERENCES ataxcode, distance DECIMAL(19,5) NOT NULL default 0, " + + "cost DECIMAL(38,18) NOT NULL default 0, listprice DECIMAL(38,18) NOT NULL default 0, price DECIMAL(38,18) NOT NULL default 0, taxapct DECIMAL(8,5) NOT NULL default 0, " + + "taxbpct DECIMAL(8,5) NOT NULL default 0, taxontax BOOL NOT NULL default false, taxname TEXT " + ")"); //WORKORDERITEM UNIT