Aggiunta dettaglio costi/Prezzi x items BOM (mancano step lavorazioni)
This commit is contained in:
@@ -944,15 +944,18 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
|
||||
// calcolo il NUOVO costo e lo aggiorno...
|
||||
double totCost = 0;
|
||||
double totPrice = 0;
|
||||
int numGroupOk = 0;
|
||||
int numItemOk = 0;
|
||||
int numElems = newBomList.Count;
|
||||
// validazione e completamento BOM
|
||||
validateBom(itemGroupList, bomGenList, ref newBomList, ref totCost, ref numGroupOk, ref numItemOk);
|
||||
validateBom(itemGroupList, bomGenList, ref newBomList, ref totCost, ref totPrice, ref numGroupOk, ref numItemOk);
|
||||
// salvo BOM...
|
||||
string itemBom = JsonConvert.SerializeObject(newBomList);
|
||||
currRec.ItemBOM = itemBom;
|
||||
currRec.BomCost = totCost;
|
||||
// salvo arrotondato alla 3° decimale
|
||||
currRec.BomCost = Math.Round(totCost,3);
|
||||
currRec.BomPrice = Math.Round(totPrice,3);
|
||||
currRec.BomOk = numElems == numGroupOk;
|
||||
currRec.ItemOk = numElems == numItemOk;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
@@ -1011,11 +1014,12 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
{
|
||||
// calcolo il NUOVO costo e lo aggiorno...
|
||||
double totCost = 0;
|
||||
double totPrice = 0;
|
||||
int numGroupOk = 0;
|
||||
int numItemOk = 0;
|
||||
int numElems = bomList.Count;
|
||||
// validazione e completamento BOM
|
||||
validateBom(itemGroupList, bomGenList, ref bomList, ref totCost, ref numGroupOk, ref numItemOk);
|
||||
validateBom(itemGroupList, bomGenList, ref bomList, ref totCost, ref totPrice, ref numGroupOk, ref numItemOk);
|
||||
#if false
|
||||
// ciclo x ogni elemento della BOM, cercando x gruppo e ExtItemCode
|
||||
foreach (var item in bomList)
|
||||
@@ -1064,7 +1068,9 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
// salvo BOM...
|
||||
string itemBom = JsonConvert.SerializeObject(bomList);
|
||||
currRec.ItemBOM = itemBom;
|
||||
currRec.BomCost = totCost;
|
||||
// salvo arrotondato alla 3° decimale
|
||||
currRec.BomCost = Math.Round(totCost, 3);
|
||||
currRec.BomPrice = Math.Round(totPrice, 3);
|
||||
currRec.BomOk = numElems == numGroupOk;
|
||||
currRec.ItemOk = numElems == numItemOk;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
@@ -1116,15 +1122,18 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
|
||||
// calcolo il NUOVO costo e lo aggiorno...
|
||||
double totCost = 0;
|
||||
double totPrice = 0;
|
||||
int numGroupOk = 0;
|
||||
int numItemOk = 0;
|
||||
int numElems = bomList.Count;
|
||||
// validazione e completamento BOM
|
||||
validateBom(itemGroupList, bomGenList, ref bomList, ref totCost, ref numGroupOk, ref numItemOk);
|
||||
validateBom(itemGroupList, bomGenList, ref bomList, ref totCost, ref totPrice, ref numGroupOk, ref numItemOk);
|
||||
// salvo BOM...
|
||||
string itemBom = JsonConvert.SerializeObject(bomList);
|
||||
currRec.ItemBOM = itemBom;
|
||||
currRec.BomCost = totCost;
|
||||
// salvo arrotondato alla 3° decimale
|
||||
currRec.BomCost = Math.Round(totCost, 3);
|
||||
currRec.BomPrice = Math.Round(totPrice, 3);
|
||||
currRec.BomOk = numElems == numGroupOk;
|
||||
currRec.ItemOk = numElems == numItemOk;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
@@ -1157,17 +1166,21 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
/// Esegue completamento e la validazione dei dati BOM da lista articoli + gruppi,
|
||||
/// validando i dati stessi
|
||||
/// </summary>
|
||||
/// <param name="itemGroupList"></param>
|
||||
/// <param name="bomGenList"></param>
|
||||
/// <param name="bomList"></param>
|
||||
/// <param name="totCost"></param>
|
||||
/// <param name="numGroupOk"></param>
|
||||
/// <param name="numItemOk"></param>
|
||||
private static void validateBom(List<ItemGroupModel> itemGroupList, List<ItemModel> bomGenList, ref List<BomItemDTO> bomList, ref double totCost, ref int numGroupOk, ref int numItemOk)
|
||||
/// <param name="itemGroupList">Elenco ItemGroup da considerare</param>
|
||||
/// <param name="bomGenList">Item di tipo BOM/BomAlt</param>
|
||||
/// <param name="bomList">Lista BOM ricevuta da validare</param>
|
||||
/// <param name="totCost">Costo netto componenti BOM calcolato</param>
|
||||
/// <param name="totPrice">Prezzo complessivo calcolato (con aggiunta marginalità)</param>
|
||||
/// <param name="numGroupOk">Controllo coerenza calcoli sui gruppi items</param>
|
||||
/// <param name="numItemOk">Controllo coerenza calcoli su num items</param>
|
||||
private static void validateBom(List<ItemGroupModel> itemGroupList, List<ItemModel> bomGenList, ref List<BomItemDTO> bomList, ref double totCost, ref double totPrice, ref int numGroupOk, ref int numItemOk)
|
||||
{
|
||||
double margin = 0;
|
||||
// ciclo x ogni elemento della BOM, cercando x gruppo e ExtItemCode
|
||||
foreach (var item in bomList)
|
||||
{
|
||||
// init del margine
|
||||
margin = 0;
|
||||
// verifico item group esistente...
|
||||
if (itemGroupList.Where(x => x.CodGroup == item.ClassCode).Count() > 0)
|
||||
{
|
||||
@@ -1182,6 +1195,8 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
// conto l'item
|
||||
numItemOk++;
|
||||
item.PriceEff = item.Price;
|
||||
// dovrei recuperare margine da BOM... da rivedere, x ora cablato 20%...
|
||||
margin = 0.2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1219,6 +1234,7 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
item.ItemCode = recCost.ExtItemCode;
|
||||
//item.DescriptionCode = recCost.Name;
|
||||
}
|
||||
margin = recCost.Margin;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1228,6 +1244,8 @@ namespace EgwCoreLib.Lux.Data.Controllers
|
||||
}
|
||||
// ...e aggiorno totale
|
||||
totCost += item.TotalCost;
|
||||
// e prezzo totale compreso margine
|
||||
totPrice += item.TotalCost * (1 + margin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,6 +83,11 @@ namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
/// </summary>
|
||||
public OfferStates OffertState { get; set; } = OfferStates.Open;
|
||||
|
||||
/// <summary>
|
||||
/// Sconto applicato (deve essere < del MAX)
|
||||
/// </summary>
|
||||
public double Discount { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Numero Item compresi
|
||||
/// </summary>
|
||||
@@ -93,14 +98,33 @@ namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Imposto totale offerta
|
||||
/// Costo totale offerta (rock bottom)
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public double TotalCost
|
||||
{
|
||||
get => OfferRowNav?.Sum(x => x.BomCost) ?? 0;
|
||||
get => OfferRowNav?.Sum(x => x.TotalCost) ?? 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prezzo totale offerta (compreso di amrginalità)
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public double TotalPrice
|
||||
{
|
||||
get => OfferRowNav?.Sum(x => x.TotalPrice) ?? 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sconto massimo applicabile
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public double MaxDiscount
|
||||
{
|
||||
get => (TotalCost > 0 && TotalPrice > TotalCost) ? (TotalPrice - TotalCost) / TotalPrice : 0;
|
||||
}
|
||||
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// ID Ordine (nullo se non c'è ordine)
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace EgwCoreLib.Lux.Data
|
||||
);
|
||||
|
||||
modelBuilder.Entity<GenValueModel>().HasData(
|
||||
new GenValueModel { GenValID=1, Ordinal=1, ClassCod = "WoodMat", ValString = "Pine" },
|
||||
new GenValueModel { GenValID = 1, Ordinal = 1, ClassCod = "WoodMat", ValString = "Pine" },
|
||||
new GenValueModel { GenValID = 2, Ordinal = 2, ClassCod = "WoodMat", ValString = "Maple" },
|
||||
new GenValueModel { GenValID = 3, Ordinal = 1, ClassCod = "WoodCol", ValString = "Legno" },
|
||||
new GenValueModel { GenValID = 4, Ordinal = 2, ClassCod = "WoodCol", ValString = "Bianco" },
|
||||
@@ -157,14 +157,14 @@ namespace EgwCoreLib.Lux.Data
|
||||
// init cost drivers
|
||||
modelBuilder.Entity<CostDriverModel>().HasData(
|
||||
// Risorsa principale di calcolo produttività/costi
|
||||
new CostDriverModel() { CostDriverID = 1, Name = "WorkHour", Unit = "h", Descript = "Ore lavorate per step/fase"},
|
||||
new CostDriverModel() { CostDriverID = 1, Name = "WorkHour", Unit = "h", Descript = "Ore lavorate per step/fase" },
|
||||
new CostDriverModel() { CostDriverID = 2, Name = "Meter", Unit = "m", Descript = "Metri prodotti per step/fase" },
|
||||
new CostDriverModel() { CostDriverID = 3, Name = "Unit", Unit = "#", Descript = "Numero unità prodotte (lavorate) per step/fase" }
|
||||
);
|
||||
|
||||
// inizializzazione risorse
|
||||
modelBuilder.Entity<ResourceModel>().HasData(
|
||||
new ResourceModel { ResourceID = 1, Name = "Sezionatrice", FixedCost = 12000, VariableCost=6000 , OverHeadCost= 5000, CostDriverID = 1 , CostDriverBudget= 220*4, LaborCost=30, OverHeadPerc=0.15M, EBTPerc=0.15M },
|
||||
new ResourceModel { ResourceID = 1, Name = "Sezionatrice", FixedCost = 12000, VariableCost = 6000, OverHeadCost = 5000, CostDriverID = 1, CostDriverBudget = 220 * 4, LaborCost = 30, OverHeadPerc = 0.15M, EBTPerc = 0.15M },
|
||||
new ResourceModel { ResourceID = 2, Name = "Linea SAOMAD WoodPecker Just 3500", FixedCost = 100000, VariableCost = 30000, OverHeadCost = 15000, CostDriverID = 1, CostDriverBudget = 220 * 8, LaborCost = 40, OverHeadPerc = 0.15M, EBTPerc = 0.15M },
|
||||
new ResourceModel { ResourceID = 3, Name = "Linea Pantografo", FixedCost = 24000, VariableCost = 6000, OverHeadCost = 5000, CostDriverID = 1, CostDriverBudget = 220 * 8, LaborCost = 35, OverHeadPerc = 0.15M, EBTPerc = 0.15M },
|
||||
new ResourceModel { ResourceID = 4, Name = "Stazione Verniciatura", FixedCost = 24000, VariableCost = 6000, OverHeadCost = 3000, CostDriverID = 1, CostDriverBudget = 220 * 4, LaborCost = 30, OverHeadPerc = 0.15M, EBTPerc = 0.15M },
|
||||
@@ -234,9 +234,9 @@ namespace EgwCoreLib.Lux.Data
|
||||
|
||||
// inizializzazione dei valori di default x OfferRow
|
||||
modelBuilder.Entity<OfferRowModel>().HasData(
|
||||
new OfferRowModel { OfferRowID = 1, OfferID = 1, OfferRowUID = $"OFF{DateTime.Today:yy}0000000001", Inserted = DateTime.Now, Modified = DateTime.Now, BomCost = 950, SellingItemID = 1, Qty = 3, RowNum = 1, SerStruct = "{}", Note = "Finestra anta singola 2025", ItemSteps = "{}", BomOk = true, ItemOk = true },
|
||||
new OfferRowModel { OfferRowID = 2, OfferID = 1, OfferRowUID = $"OFF{DateTime.Today:yy}0000000002", Inserted = DateTime.Now, Modified = DateTime.Now, BomCost = 160, SellingItemID = 2, Qty = 3, RowNum = 2, SerStruct = "{}", Note = "Persiana per Finestra anta singola 2025", ItemSteps = "{}", BomOk = true, ItemOk = true },
|
||||
new OfferRowModel { OfferRowID = 3, OfferID = 1, OfferRowUID = $"OFF{DateTime.Today:yy}0000000003", Inserted = DateTime.Now, Modified = DateTime.Now, BomCost = 200, SellingItemID = 3, Qty = 3, RowNum = 3, SerStruct = "{}", Note = "Installazione serramento", ItemSteps = "{}", BomOk = true, ItemOk = true }
|
||||
new OfferRowModel { OfferRowID = 1, OfferID = 1, OfferRowUID = $"OFF{DateTime.Today:yy}0000000001", Inserted = DateTime.Now, Modified = DateTime.Now, BomCost = 900, BomPrice = 950, SellingItemID = 1, Qty = 3, RowNum = 1, SerStruct = "{}", Note = "Finestra anta singola 2025", ItemSteps = "{}", BomOk = true, ItemOk = true },
|
||||
new OfferRowModel { OfferRowID = 2, OfferID = 1, OfferRowUID = $"OFF{DateTime.Today:yy}0000000002", Inserted = DateTime.Now, Modified = DateTime.Now, BomCost = 160, BomPrice = 200, SellingItemID = 2, Qty = 3, RowNum = 2, SerStruct = "{}", Note = "Persiana per Finestra anta singola 2025", ItemSteps = "{}", BomOk = true, ItemOk = true },
|
||||
new OfferRowModel { OfferRowID = 3, OfferID = 1, OfferRowUID = $"OFF{DateTime.Today:yy}0000000003", Inserted = DateTime.Now, Modified = DateTime.Now, BomCost = 200, BomPrice = 250, SellingItemID = 3, Qty = 3, RowNum = 3, SerStruct = "{}", Note = "Installazione serramento", ItemSteps = "{}", BomOk = true, ItemOk = true }
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>0.9.2509.2311</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="ExtLib\**" />
|
||||
<Content Remove="ExtLib\**" />
|
||||
<EmbeddedResource Remove="ExtLib\**" />
|
||||
<None Remove="ExtLib\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Controllers\JwdController.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="DemoData\AntaDoppia.jwd" />
|
||||
<None Remove="DemoData\AntaSingola.jwd" />
|
||||
<None Remove="DemoData\FinDueAnteBottomFisso.jwd" />
|
||||
<None Remove="DemoData\FinestraSplitVert.jwd" />
|
||||
<None Remove="DemoData\FinestraSplitVertOriz.jwd" />
|
||||
<None Remove="DemoImg\AntaDoppia.svg" />
|
||||
<None Remove="DemoImg\AntaSingola.svg" />
|
||||
<None Remove="DemoImg\Window01.jpg" />
|
||||
<None Remove="DemoImg\Window01.png" />
|
||||
<None Remove="DemoImg\Window01.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="DemoData\AntaDoppia.jwd">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoData\AntaSingola.jwd">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoData\FinDueAnteBottomFisso.jwd">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoData\FinestraSplitVert.jwd">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoData\FinestraSplitVertOriz.jwd">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoImg\AntaDoppia.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoImg\AntaSingola.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoImg\Window01.jpg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoImg\Window01.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="DemoImg\Window01.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Egw.Lux.WebWindow.Base" Version="2.7.9-beta.1313" />
|
||||
<PackageReference Include="EgwMultiEngineManager.Data" Version="2.7.9-beta.1" />
|
||||
<PackageReference Include="NLog" Version="6.0.1" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="6.0.1" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\EgwCoreLib.Lux.Core\EgwCoreLib.Lux.Core.csproj" />
|
||||
<ProjectReference Include="..\EgwCoreLib.Lux.Data\EgwCoreLib.Lux.Data.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="logs\.placeholder">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
|
||||
<Exec Command="powershell.exe -ExecutionPolicy Unrestricted -NoProfile -NonInteractive -File $(ProjectDir)\post-build.ps1 -ProjectDir $(ProjectDir) -ProjectPath $(ProjectPath)" />
|
||||
</Target>
|
||||
</Project>
|
||||
|
||||
@@ -45,8 +45,9 @@ else
|
||||
<th>Codice</th>
|
||||
<th>Descrizione</th>
|
||||
<th class="text-end">Qty</th>
|
||||
<th class="text-end">Importo </th>
|
||||
<th class="text-end">Tot</th>
|
||||
<th class="text-end">Importo</th>
|
||||
<th class="text-end">Totale</th>
|
||||
<th class="text-end">Marg.</th>
|
||||
@if (DisplayMode == EgwCoreLib.Lux.Core.Enums.DisplayMode.Edit)
|
||||
{
|
||||
<th class="text-end" title="Cambio Materiali">Mat.</th>
|
||||
@@ -76,18 +77,29 @@ else
|
||||
<td>@item.OfferRowUID</td>
|
||||
<td>@item.Note</td>
|
||||
<td class="text-end">@item.Qty</td>
|
||||
<td class="text-end">
|
||||
@if (!(item.BomOk && item.ItemOk))
|
||||
{
|
||||
<span class="text-danger me-2" title=""><i class="fa-solid fa-triangle-exclamation"></i></span>
|
||||
}
|
||||
@($"{item.BomCost:C2}")
|
||||
<td class="text-end text-nowrap">
|
||||
<div class="fw-bold" title="Prezzo Finito">
|
||||
@if (!(item.BomOk && item.ItemOk))
|
||||
{
|
||||
<span class="text-danger me-2" title=""><i class="fa-solid fa-triangle-exclamation"></i></span>
|
||||
}
|
||||
@($"{item.UnitPrice:C2}")
|
||||
</div>
|
||||
<div class="small text-secondary" title="RockBottom Price">(@item.UnitCost.ToString("C2"))</div>
|
||||
</td>
|
||||
<td class="text-end text-nowrap">
|
||||
<div class="fw-bold" title="Prezzo Finito">
|
||||
@($"{item.TotalPrice:C2}")
|
||||
</div>
|
||||
<div class="small text-secondary" title="RockBottom Price">(@item.TotalCost.ToString("C2"))</div>
|
||||
</td>
|
||||
<td class="text-end text-nowrap" title="Margine / Sconto MAX applicabile">
|
||||
@item.MaxDiscount.ToString("P2")
|
||||
</td>
|
||||
<td class="text-end fw-bold">@($"{item.TotalCost:C2}")</td>
|
||||
@if (DisplayMode == EgwCoreLib.Lux.Core.Enums.DisplayMode.Edit)
|
||||
{
|
||||
<td class="text-end">
|
||||
@if(!string.IsNullOrEmpty(item.ItemBOM))
|
||||
@if (!string.IsNullOrEmpty(item.ItemBOM))
|
||||
{
|
||||
<button class="btn btn-sm btn-info" title="cambio materiali assegnati" @onclick="() => DoSwapMat(item)"><i class="fa-solid fa-arrow-right-arrow-left"></i></button>
|
||||
}
|
||||
|
||||
@@ -130,6 +130,7 @@ else
|
||||
}
|
||||
<th class="text-end"># articoli</th>
|
||||
<th class="text-end">Importo</th>
|
||||
<th class="text-end">Marg.</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -165,7 +166,11 @@ else
|
||||
@item.NumItems
|
||||
</td>
|
||||
<td class="text-end">
|
||||
@item.TotalCost.ToString("C2")
|
||||
<div class="fw-bold" title="Prezzo Finito">@item.TotalPrice.ToString("C2")</div>
|
||||
<div class="small text-secondary" title="RockBottom Price">(@item.TotalCost.ToString("C2"))</div>
|
||||
</td>
|
||||
<td class="text-end" title="Margine / Sconto MAX applicabile">
|
||||
@item.MaxDiscount.ToString("P2")
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user