This commit is contained in:
2021-05-21 22:10:51 +00:00
parent 41b17700a6
commit 3f761e64ca
3 changed files with 178 additions and 80 deletions

View File

@@ -2916,7 +2916,7 @@ namespace AyaNova.Biz
return null; return null;
else else
{ {
await PartBizActionsAsync(AyaEvent.Created, newObject, null, null); //await PartBizActionsAsync(AyaEvent.Created, newObject, null, null);
//newObject.Tags = TagBiz.NormalizeTags(newObject.Tags); //newObject.Tags = TagBiz.NormalizeTags(newObject.Tags);
//newObject.CustomFields = JsonUtil.CompactJson(newObject.CustomFields); //newObject.CustomFields = JsonUtil.CompactJson(newObject.CustomFields);
await ct.WorkOrderItemPart.AddAsync(newObject); await ct.WorkOrderItemPart.AddAsync(newObject);
@@ -2962,7 +2962,7 @@ namespace AyaNova.Biz
await PartValidateAsync(putObject, dbObject); await PartValidateAsync(putObject, dbObject);
if (HasErrors) return null; if (HasErrors) return null;
await PartBizActionsAsync(AyaEvent.Modified, putObject, dbObject, null); // await PartBizActionsAsync(AyaEvent.Modified, putObject, dbObject, null);
ct.Replace(dbObject, putObject); ct.Replace(dbObject, putObject);
try try
{ {
@@ -3044,97 +3044,189 @@ namespace AyaNova.Biz
// //
private async Task PartPopulateVizFields(WorkOrderItemPart o) private async Task PartPopulateVizFields(WorkOrderItemPart o)
{ {
await Task.CompletedTask; if (o.PartWarehouseId != 0)
// if (o.WorkOrderOverseerId != null) o.PartWarehouseViz = await ct.PartWarehouse.AsNoTracking().Where(x => x.Id == o.PartWarehouseId).Select(x => x.Name).FirstOrDefaultAsync();
// o.WorkOrderOverseerViz = await ct.User.AsNoTracking().Where(x => x.Id == o.WorkOrderOverseerId).Select(x => x.Name).FirstOrDefaultAsync(); Part part = null;
} if (o.PartId != 0)
part = await ct.Part.AsNoTracking().FirstOrDefaultAsync(x => x.Id == o.PartId);
TaxCode Tax = null;
if (o.TaxPartSaleId != null)
Tax = await ct.TaxCode.AsNoTracking().FirstOrDefaultAsync(z => z.Id == o.TaxPartSaleId);
if (Tax != null)
o.TaxPartSaleViz = Tax.Name;
//////////////////////////////////////////////////////////////////////////////////////////////// o.PriceViz = 0;
//BIZ ACTIONS if (part != null)
//
//
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 o.CostViz = part.Cost;
if (newObj.PartId == oldObj.PartId) o.ListPriceViz = part.Retail;
{ o.UnitOfMeasureViz = part.UnitOfMeasure;
ApplyPricingUpdate = false; o.PriceViz = part.Retail;//default price used if not manual or contract override
}
//If taxes haven't change then no need to update taxes
if (newObj.TaxPartSaleId == oldObj.TaxPartSaleId)
ApplyTax = false;
} }
//Tax code //manual price overrides anything
if (ApplyTax) if (o.PriceOverride != null)
o.PriceViz = (decimal)o.PriceOverride;
else
{ {
//Default in case nothing to apply //not manual so could potentially have a contract adjustment
newObj.TaxAPct = 0; var c = await GetCurrentWorkOrderContractFromRelatedAsync(AyaType.WorkOrderItem, o.WorkOrderItemId);
newObj.TaxBPct = 0; if (c != null)
newObj.TaxOnTax = false;
if (newObj.TaxPartSaleId != null)
{ {
var t = await ct.TaxCode.AsNoTracking().FirstOrDefaultAsync(z => z.Id == newObj.TaxPartSaleId); decimal pct = 0;
if (t != null) ContractOverrideType cot = ContractOverrideType.PriceDiscount;
bool TaggedAdjustmentInEffect = false;
//POTENTIAL CONTRACT ADJUSTMENTS
//First check if there is a matching tagged contract discount, that takes precedence
if (c.ContractPartOverrideItems.Count > 0)
{ {
newObj.TaxAPct = t.TaxAPct; //Iterate all contract tagged items in order of ones with the most tags first
newObj.TaxBPct = t.TaxBPct; foreach (var cp in c.ContractPartOverrideItems.OrderByDescending(z => z.Tags.Count))
newObj.TaxOnTax = t.TaxOnTax; if (cp.Tags.All(z => part.Tags.Any(x => x == z)))
{
if (cp.OverridePct != 0)
{
pct = cp.OverridePct / 100;
cot = cp.OverrideType;
TaggedAdjustmentInEffect = true;
}
}
}
//Generic discount?
if (!TaggedAdjustmentInEffect && c.ServiceRatesOverridePct != 0)
{
pct = c.ServiceRatesOverridePct / 100;
cot = c.ServiceRatesOverrideType;
}
//apply if discount found
if (pct != 0)
{
if (cot == ContractOverrideType.CostMarkup)
o.PriceViz = o.CostViz + (o.CostViz * pct);
else if (cot == ContractOverrideType.PriceDiscount)
o.PriceViz = o.ListPriceViz - (o.ListPriceViz * pct);
} }
} }
} }
//Pricing //Calculate totals and taxes
if (ApplyPricingUpdate) //NET
{ o.NetViz = o.PriceViz * o.Quantity;
//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); //TAX
if (s != null) o.TaxAViz = 0;
o.TaxBViz = 0;
if (Tax != null)
{
if (Tax.TaxAPct != 0)
{ {
newObj.Cost = s.Cost; o.TaxAViz = o.NetViz * (Tax.TaxAPct / 100);
newObj.ListPrice = s.Retail; }
var Contract = await GetCurrentWorkOrderContractFromRelatedAsync(AyaType.WorkOrderItem, newObj.WorkOrderItemId); if (Tax.TaxBPct != 0)
PartSetListPrice(newObj, Contract); {
if (Tax.TaxOnTax)
{
o.TaxBViz = (o.NetViz + o.TaxAViz) * (Tax.TaxBPct / 100);
}
else
{
o.TaxBViz = o.NetViz * (Tax.TaxBPct / 100);
}
} }
} }
o.LineTotalViz = o.NetViz + o.TaxAViz + o.TaxBViz;
} }
//////////////////////////////////////////////////////////////////////////////////////////////// // ////////////////////////////////////////////////////////////////////////////////////////////////
// SET PER UNIT LIST PRICE // //BIZ ACTIONS
// // //
//(called by woitempart save and also by header save on change of contract) // //
private static void PartSetListPrice(WorkOrderItemPart o, Contract c) // private async Task PartBizActionsAsync(AyaEvent ayaEvent, WorkOrderItemPart newObj, WorkOrderItemPart oldObj, IDbContextTransaction transaction)
{ // {
if (c == null || c.ServiceRatesOverridePct == 0) // //automatic actions on record change, called AFTER validation
{
o.Price = o.ListPrice;//default with no contract // //currently no processing required except for created or modified at this time
return; // if (ayaEvent != AyaEvent.Created && ayaEvent != AyaEvent.Modified)
} // return;
if (c.ServiceRatesOverrideType == ContractOverrideType.CostMarkup)
o.Price = o.Cost + (o.Cost * c.ServiceRatesOverridePct); // //SET TAXES AND PRICING
else if (c.ServiceRatesOverrideType == ContractOverrideType.PriceDiscount)
o.Price = o.ListPrice - (o.ListPrice * c.ServiceRatesOverridePct); // //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
// //
// //(called by woitempart save and also by header save on change of contract)
// private static void PartSetListPrice(WorkOrderItemPart o, Contract c)
// {
// if (c == null || c.ServiceRatesOverridePct == 0)
// {
// o.Price = o.ListPrice;//default with no contract
// return;
// }
// if (c.ServiceRatesOverrideType == ContractOverrideType.CostMarkup)
// o.Price = o.Cost + (o.Cost * c.ServiceRatesOverridePct);
// else if (c.ServiceRatesOverrideType == ContractOverrideType.PriceDiscount)
// o.Price = o.ListPrice - (o.ListPrice * c.ServiceRatesOverridePct);
// }
//////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -20,9 +20,9 @@ namespace AyaNova.Models
[Required] [Required]
public decimal TaxPaid { get; set; } public decimal TaxPaid { get; set; }
public long? ChargeTaxCodeId { get; set; } public long? ChargeTaxCodeId { get; set; }
[NotMapped] [NotMapped]
public string ChargeTaxCodeViz { get; set; } public string ChargeTaxCodeViz { get; set; }
public bool ReimburseUser { get; set; } = false; public bool ReimburseUser { get; set; } = false;
public long? UserId { get; set; } public long? UserId { get; set; }
[NotMapped] [NotMapped]

View File

@@ -15,11 +15,17 @@ namespace AyaNova.Models
public string Serials { get; set; } public string Serials { get; set; }
[Required] [Required]
public long PartId { get; set; } public long PartId { get; set; }
[NotMapped]
public string PartViz { get; set; }
[Required] [Required]
public long PartWarehouseId { get; set; } public long PartWarehouseId { get; set; }
[NotMapped]
public string PartWarehouseViz { get; set; }
[Required] [Required]
public decimal Quantity { get; set; } public decimal Quantity { get; set; }
public long? TaxPartSaleId { get; set; } public long? TaxPartSaleId { get; set; }
[NotMapped]
public string TaxPartSaleViz { get; set; }
// //PRICE FIELDS // //PRICE FIELDS
// [Required] // [Required]
@@ -43,7 +49,7 @@ namespace AyaNova.Models
// [NotMapped] // [NotMapped]
// public decimal LineTotalViz { get; set; } // public decimal LineTotalViz { get; set; }
//Standard pricing fields (mostly to support printed reports though some show in UI) //Standard pricing fields (mostly to support printed reports though some show in UI)
//some not to be sent with record depending on role (i.e. cost and charge in some cases) //some not to be sent with record depending on role (i.e. cost and charge in some cases)
public decimal? PriceOverride { get; set; }//user entered manually overridden price, if null then ignored in calcs otherwise this *is* the price even if zero public decimal? PriceOverride { get; set; }//user entered manually overridden price, if null then ignored in calcs otherwise this *is* the price even if zero
[NotMapped] [NotMapped]