Compare commits
155 Commits
PreDataRefactor
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 14f0a59735 | |||
| 2fda59f6f0 | |||
| b0e1dcee8a | |||
| d8abf28daa | |||
| 2e40246d1f | |||
| 1e6efc742f | |||
| c1db6ca7af | |||
| 29765b910c | |||
| 742243a535 | |||
| 4b5c8b2252 | |||
| c80e6dbf48 | |||
| c071537424 | |||
| f91edeee5e | |||
| 190495b7db | |||
| 27f9277f6b | |||
| 7ef594326d | |||
| 53e69c0b78 | |||
| fe03d05930 | |||
| e6914a4844 | |||
| 0685c93139 | |||
| f91920790e | |||
| 2020eb6345 | |||
| e2028e0a4f | |||
| 60b054670d | |||
| 019d92c270 | |||
| e5bc914931 | |||
| ca7c964eb1 | |||
| d45bbf6584 | |||
| c736cbc801 | |||
| 946397bede | |||
| f1d4c26764 | |||
| 0e6faace39 | |||
| 12d1090540 | |||
| 869ec0ef1c | |||
| a59e256c98 | |||
| 67b8d15334 | |||
| bea6909bee | |||
| 60ecb70e38 | |||
| a154539950 | |||
| 3b3a02580e | |||
| 2a18895363 | |||
| 6cf54dc715 | |||
| 02f0150d09 | |||
| d4cfe83a9e | |||
| 23bf2f0b65 | |||
| ae68fe976d | |||
| 3f839c17f1 | |||
| 9d0c18c3b8 | |||
| 4c1d09942f | |||
| 32b5a94a51 | |||
| 17201d746f | |||
| 4cef12e37f | |||
| 0e1c22f96b | |||
| 3124f08474 | |||
| f8441f933f | |||
| e987a80d29 | |||
| c5d3ee3504 | |||
| 8c957edad8 | |||
| 84144b4beb | |||
| 151224bc56 | |||
| b2b3ed53e1 | |||
| 29112f8f48 | |||
| 320d2626fb | |||
| 00868a24c0 | |||
| db89b3d0d3 | |||
| a288ed6a5b | |||
| 9388ad6493 | |||
| ec58c870ea | |||
| 4916dd42ff | |||
| 4aa21de3b7 | |||
| 1b4c4d7cb8 | |||
| 10cecc4139 | |||
| 1cc55a6057 | |||
| 669b5b36f1 | |||
| 252f07cb29 | |||
| 07eacd022e | |||
| 72a880fb11 | |||
| 0d5e3b6698 | |||
| a205f4f77e | |||
| 40193db94f | |||
| 1d5e80df53 | |||
| 9f8ce27816 | |||
| 7b4b3294f0 | |||
| 85ea97634e | |||
| 72627f8128 | |||
| 912af1e60e | |||
| fd40a6906f | |||
| 2b97d85014 | |||
| 3081e8a908 | |||
| 0b58359db7 | |||
| d4f26def6f | |||
| 1ec15d956d | |||
| d2de5f4657 | |||
| 3b311a8ce1 | |||
| 95ed44155b | |||
| 8d9ddaa4a0 | |||
| b375148943 | |||
| 58f130e059 | |||
| 2310fa020a | |||
| 2c1bf139c9 | |||
| e3b9c6e0e7 | |||
| e73766589d | |||
| f59d4c9876 | |||
| b629b5ce1f | |||
| cb51e3f7fc | |||
| 5593ddc7fc | |||
| edaa834a9c | |||
| 490011bae5 | |||
| cc9e69efda | |||
| 7b72561b8f | |||
| 0d47f1ae7c | |||
| 35ba495030 | |||
| 274f0ed3ae | |||
| 0b3fb477dd | |||
| dc63e7677d | |||
| 66e8eae0f1 | |||
| 3964eddd45 | |||
| b1d69ba8f8 | |||
| 93ffb43953 | |||
| fc5c4f6abd | |||
| 36e3c59114 | |||
| d587ee3a45 | |||
| 99d64bdb60 | |||
| 0214ebec10 | |||
| e52d64bd08 | |||
| 349cce9462 | |||
| e5f0d7976a | |||
| 273fa4fc0c | |||
| 0813e3b2d2 | |||
| b55d30654f | |||
| ea228a9691 | |||
| a6f42b827e | |||
| 5b74509348 | |||
| 0404435ec3 | |||
| f5181dd4f3 | |||
| 870cf85e3f | |||
| 3ec1511aec | |||
| 9989c7767e | |||
| 7c5adc9012 | |||
| 0f61efdf58 | |||
| 3079068c62 | |||
| f70814d444 | |||
| afaa9a5516 | |||
| 8195f63702 | |||
| ac6695e7b0 | |||
| 2e05e8cac6 | |||
| 9e1946c636 | |||
| d560cf97d9 | |||
| 6a1e5ff3f3 | |||
| 5d656f2dce | |||
| 179d358604 | |||
| 26f64d1ecf | |||
| 8897c3cc3b | |||
| 2588ef155c | |||
| ae634079f9 |
@@ -8,8 +8,8 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageVersion>
|
||||
<PackageVersion Include="Egw.Lux.WebWindow.Base" Version="3.1.3.916" />
|
||||
<PackageVersion Include="Egw.Lux.WebWindowComplex" Version="3.1.3.916" />
|
||||
<PackageVersion Include="Egw.Lux.WebWindow.Base" Version="3.1.3.2010" />
|
||||
<PackageVersion Include="Egw.Lux.WebWindowComplex" Version="3.1.3.2010" />
|
||||
<PackageVersion Include="Egw.Window.Data" Version="2.8.1.2611" />
|
||||
<PackageVersion Include="EgwCoreLib.Razor" Version="1.5.2511.312" />
|
||||
<PackageVersion Include="EgwCoreLib.Utils" Version="1.5.2511.312" />
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EgwCoreLib.Lux.Core
|
||||
{
|
||||
public static class CloneExtensions
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Clone profondo tramite serializzazione/deserializzazione di obj generici
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public static T DeepClone<T>(this T obj)
|
||||
{
|
||||
// Configurazione serializzatore JSON per risolvere errore di loop circolare
|
||||
var JSSettings = new JsonSerializerSettings()
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||||
};
|
||||
var json = JsonConvert.SerializeObject(obj, JSSettings);
|
||||
return JsonConvert.DeserializeObject<T>(json)!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Comparatore statico tra entità
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="original"></param>
|
||||
/// <param name="edited"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsChanged<T>(T original, T edited) => !EqualityComparer<T>.Default.Equals(original, edited);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,19 @@
|
||||
{
|
||||
#region Public Enums
|
||||
|
||||
/// <summary>
|
||||
/// Stato compilazione offerta
|
||||
/// </summary>
|
||||
public enum CompileStep
|
||||
{
|
||||
Draft = 0,
|
||||
Header = 1,
|
||||
General,
|
||||
Rows,
|
||||
Delivery,
|
||||
FinalCheck
|
||||
}
|
||||
|
||||
public enum DisplayMode
|
||||
{
|
||||
Standard,
|
||||
@@ -44,6 +57,27 @@
|
||||
JobCycle
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tipologia immagine
|
||||
/// </summary>
|
||||
public enum ImageType
|
||||
{
|
||||
/// <summary>
|
||||
/// Non definita (da calcolare...)
|
||||
/// </summary>
|
||||
ND = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Calcolata (es JWD, BTL)
|
||||
/// </summary>
|
||||
Calculated,
|
||||
|
||||
/// <summary>
|
||||
/// Fissa (tipicamente prodotto da rivendita/servizio)
|
||||
/// </summary>
|
||||
Fixed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tipologia item (classe/natura articolo)
|
||||
/// </summary>
|
||||
@@ -77,25 +111,6 @@
|
||||
BomAlt
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tipologia immagine
|
||||
/// </summary>
|
||||
public enum ImageType
|
||||
{
|
||||
/// <summary>
|
||||
/// Non definita (da calcolare...)
|
||||
/// </summary>
|
||||
ND = 0,
|
||||
/// <summary>
|
||||
/// Calcolata (es JWD, BTL)
|
||||
/// </summary>
|
||||
Calculated,
|
||||
/// <summary>
|
||||
/// Fissa (tipicamente prodotto da rivendita/servizio)
|
||||
/// </summary>
|
||||
Fixed
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tipologia item per Source (modalità costruzione)
|
||||
/// </summary>
|
||||
@@ -205,6 +220,34 @@
|
||||
MACHINABLE = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tipo di code del Prod
|
||||
/// </summary>
|
||||
public enum ProdQueueType
|
||||
{
|
||||
waiting,
|
||||
running,
|
||||
done
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Modalità raggruppamento (giornalieri, orari...)
|
||||
/// </summary>
|
||||
public enum RuidGroupMode
|
||||
{
|
||||
Day,
|
||||
Hour
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tipo di dati raggruppamento gestiti
|
||||
/// </summary>
|
||||
public enum RuidTagMode
|
||||
{
|
||||
Envir,
|
||||
Mode
|
||||
}
|
||||
|
||||
#endregion Public Enums
|
||||
|
||||
#if false
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace EgwCoreLib.Lux.Core.Generic
|
||||
{
|
||||
public class EditStepDto
|
||||
{
|
||||
public Enums.CompileStep SrcStep { get; set; }
|
||||
public bool Changed { get; set; } = false;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +1,12 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Stats;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Stock;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
using EgwCoreLib.Lux.Data.Repository.Config;
|
||||
using EgwCoreLib.Lux.Data.Repository.Cost;
|
||||
using EgwCoreLib.Lux.Data.Repository.Items;
|
||||
using EgwCoreLib.Lux.Data.Repository.Job;
|
||||
using EgwCoreLib.Lux.Data.Repository.Production;
|
||||
using EgwCoreLib.Lux.Data.Repository.Sales;
|
||||
using EgwCoreLib.Lux.Data.Repository.Stats;
|
||||
using EgwCoreLib.Lux.Data.Repository.Utils;
|
||||
using EgwCoreLib.Lux.Data.Services.Config;
|
||||
using EgwCoreLib.Lux.Data.Services.Cost;
|
||||
using EgwCoreLib.Lux.Data.Services.General;
|
||||
using EgwCoreLib.Lux.Data.Services.Internal;
|
||||
using EgwCoreLib.Lux.Data.Services.Items;
|
||||
using EgwCoreLib.Lux.Data.Services.Job;
|
||||
using EgwCoreLib.Lux.Data.Services.Production;
|
||||
using EgwCoreLib.Lux.Data.Services.Sales;
|
||||
using EgwCoreLib.Lux.Data.Services.Stats;
|
||||
using EgwCoreLib.Lux.Data.Services.Utils;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data
|
||||
{
|
||||
public static class DataServiceCollectionExtensions
|
||||
{
|
||||
public static IServiceCollection AddLuxData(this IServiceCollection services, string connectionString)
|
||||
{
|
||||
//// DbContextFactory: preferibile in Blazor Server e scenari concorrenti
|
||||
//services.AddDbContextFactory<DataLayerContext>(options =>
|
||||
// options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString)));
|
||||
|
||||
// servizi preliminari
|
||||
//services.TryAddSingleton<IConnectionMultiplexer>(redisConn);
|
||||
services.TryAddSingleton<IRedisService, RedisService>();
|
||||
services.TryAddSingleton<RedisSubscriptionManager>();
|
||||
|
||||
// Repository Scoped
|
||||
services.TryAddScoped<IConfGlassRepository, ConfGlassRepository>();
|
||||
services.TryAddScoped<IConfProfileRepository, ConfProfileRepository>();
|
||||
services.TryAddScoped<IConfWoodRepository, ConfWoodRepository>();
|
||||
services.TryAddScoped<ICostDriverRepository, CostDriverRepository>();
|
||||
services.TryAddScoped<ICustomerRepository, CustomerRepository>();
|
||||
services.TryAddScoped<IDealerRepository, DealerRepository>();
|
||||
services.TryAddScoped<IEnvirParamRepository, EnvirParamRepository>();
|
||||
services.TryAddScoped<IGenClassRepository, GenClassRepository>();
|
||||
services.TryAddScoped<IGenValRepository, GenValRepository>();
|
||||
services.TryAddScoped<IItemGroupRepository, ItemGroupRepository>();
|
||||
services.TryAddScoped<IItemRepository, ItemRepository>();
|
||||
services.TryAddScoped<IJobStepRepository, JobStepRepository>();
|
||||
services.TryAddScoped<IJobTaskRepository, JobTaskRepository>();
|
||||
services.TryAddScoped<IOfferRepository, OfferRepository>();
|
||||
services.TryAddScoped<IOfferRowRepository, OfferRowRepository>();
|
||||
services.TryAddScoped<IOrderRepository, OrderRepository>();
|
||||
services.TryAddScoped<IOrderRowRepository, OrderRowRepository>();
|
||||
services.TryAddScoped<IPhaseRepository, PhaseRepository>();
|
||||
services.TryAddScoped<IProductionBatchRepository, ProductionBatchRepository>();
|
||||
services.TryAddScoped<IProductionGroupRepository, ProductionGroupRepository>();
|
||||
services.TryAddScoped<IProductionItemRepository, ProductionItemRepository>();
|
||||
services.TryAddScoped<IProductionOdlRepository, ProductionOdlRepository>();
|
||||
services.TryAddScoped<IProductionPlantRepository, ProductionPlantRepository>();
|
||||
services.TryAddScoped<IResourceRepository, ResourceRepository>();
|
||||
services.TryAddScoped<ISellingItemRepository, SellingItemRepository>();
|
||||
services.TryAddScoped<IStatsAggrRepository, StatsAggrRepository>();
|
||||
services.TryAddScoped<IStatsDetailRepository, StatsDetailRepository>();
|
||||
services.TryAddScoped<ITagRepository, TagRepository>();
|
||||
services.TryAddScoped<ITemplateRepository, TemplateRepository>();
|
||||
services.TryAddScoped<ITemplateRowRepository, TemplateRowRepository>();
|
||||
|
||||
// Servizi Scoped
|
||||
services.TryAddScoped<IConfGlassService, ConfGlassService>();
|
||||
services.TryAddScoped<IConfProfileService, ConfProfileService>();
|
||||
services.TryAddScoped<IConfWoodService, ConfWoodService>();
|
||||
services.TryAddScoped<ICostDriverService, CostDriverService>();
|
||||
services.TryAddScoped<ICustomerService, CustomerService>();
|
||||
services.TryAddScoped<IDealerService, DealerService>();
|
||||
services.TryAddScoped<IEnvirParamService, EnvirParamService>();
|
||||
services.TryAddScoped<IGenClassService, GenClassService>();
|
||||
services.TryAddScoped<IGenValService, GenValService>();
|
||||
services.TryAddScoped<IItemService, ItemService>();
|
||||
services.TryAddScoped<IItemGroupService, ItemGroupService>();
|
||||
services.TryAddScoped<IJobStepService, JobStepService>();
|
||||
services.TryAddScoped<IJobTaskService, JobTaskService>();
|
||||
services.TryAddScoped<IOfferService, OfferService>();
|
||||
services.TryAddScoped<IOfferRowService, OfferRowService>();
|
||||
services.TryAddScoped<IOrderService, OrderService>();
|
||||
services.TryAddScoped<IOrderRowService, OrderRowService>();
|
||||
services.TryAddScoped<IPhaseService, PhaseService>();
|
||||
services.TryAddScoped<IProductionGroupService, ProductionGroupService>();
|
||||
services.TryAddScoped<IProductionItemService, ProductionItemService>();
|
||||
services.TryAddScoped<IProductionBatchService, ProductionBatchService>();
|
||||
services.TryAddScoped<IProductionOdlService, ProductionOdlService>();
|
||||
services.TryAddScoped<IProductionPlantService, ProductionPlantService>();
|
||||
services.TryAddScoped<IResourceService, ResourceService>();
|
||||
services.TryAddScoped<ISellingItemService, SellingItemService>();
|
||||
services.TryAddScoped<IStatsAggrService, StatsAggrService>();
|
||||
services.TryAddScoped<IStatsDetailService, StatsDetailService>();
|
||||
services.TryAddScoped<ITagService, TagService>();
|
||||
services.TryAddScoped<ITemplateService, TemplateService>();
|
||||
services.TryAddScoped<ITemplateRowService, TemplateRowService>();
|
||||
|
||||
// Facade / DataLayerService
|
||||
services.TryAddScoped<IDataLayerServices, DataLayerServices>();
|
||||
services.TryAddScoped<ICalcRuidService, CalcRuidService>();
|
||||
//builder.Services.AddSingleton<DataLayerServices>();
|
||||
//services.TryAddScoped<IDataLayerServices, DataLayerServices>();
|
||||
|
||||
// aggiunta servizi finali Singleton...
|
||||
services.TryAddSingleton<IImageCacheService, ImageCacheService>();
|
||||
services.TryAddSingleton<IConfigDataService, ConfigDataService>();
|
||||
services.TryAddSingleton<ICalcRequestService, CalcRequestService>();
|
||||
services.TryAddSingleton<IFileService, FileService>();
|
||||
services.TryAddSingleton<IProdService, ProdService>();
|
||||
//services.TryAddSingleton<CalcRequestService>();
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Catalog
|
||||
{
|
||||
/// <summary>
|
||||
/// Classe dei template di oggetti gestiti
|
||||
+1
-1
@@ -6,7 +6,7 @@ using static EgwCoreLib.Lux.Core.Enums;
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Catalog
|
||||
{
|
||||
[Table("sales_template_row")]
|
||||
public class TemplateRowModel
|
||||
@@ -1,5 +1,5 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
@@ -126,6 +126,12 @@ namespace EgwCoreLib.Lux.Data.DbModel.Items
|
||||
get => false;
|
||||
}
|
||||
|
||||
[NotMapped]
|
||||
public bool HasBOM
|
||||
{
|
||||
get => SourceType == ItemSourceType.Jwd || SourceType == ItemSourceType.FileBTL;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Navigazione Job/Cicli
|
||||
/// </summary>
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ using System.Threading.Tasks;
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// Configurazione JobDriver abilitati per un Job e relativi coefficienti di conversione verso CostDriver
|
||||
+1
-1
@@ -7,7 +7,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// Definizione driver di calcolo dall'Engine x la stima del CostDriver equivalente tempi/costi
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
[Table("task_job_step_item")]
|
||||
public class JobStepItemModel
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Utils;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
@@ -7,7 +7,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// Routing dei cicli di lavoro, con riferimento a risorse e fasi
|
||||
+1
-1
@@ -6,7 +6,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
[Table("task_job_step_tag")]
|
||||
public class JobStepTagModel
|
||||
+1
-1
@@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// Definizione macro dei Cicli di Lavoro / Job
|
||||
+1
-1
@@ -6,7 +6,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
[Table("task_job_task_tag")]
|
||||
public class JobTaskTagModel
|
||||
+1
-1
@@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
||||
// <Auto-Generated>
|
||||
// This is here so CodeMaid doesn't reorganize this document
|
||||
// </Auto-Generated>
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Task
|
||||
namespace EgwCoreLib.Lux.Data.DbModel.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// Fase di lavorazione / ProductionStage
|
||||
@@ -1,5 +1,5 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using EgwCoreLib.Lux.Core.Generic;
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
@@ -50,10 +51,15 @@ namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
/// <summary>
|
||||
/// ID dell'articolo di vendita offerto
|
||||
/// </summary>
|
||||
public int SellingItemID { get; set; }
|
||||
public int? SellingItemID { get; set; }
|
||||
/// <summary>
|
||||
/// Definisce se sia calcolabile, dato il tipo SellingItem
|
||||
/// </summary>
|
||||
[NotMapped]
|
||||
public bool IsNote => SellingItemID == null;
|
||||
|
||||
/// <summary>
|
||||
/// Riferimento (opzionale9 al template da cui è derivato
|
||||
/// Riferimento (opzionale) al template da cui è derivato
|
||||
/// </summary>
|
||||
public int? TemplateRowID { get; set; } = null;
|
||||
|
||||
@@ -64,16 +70,6 @@ namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
public bool CalcEnabled
|
||||
{
|
||||
get => ImgType == ImageType.Calculated;
|
||||
#if false
|
||||
{
|
||||
bool answ = false;
|
||||
if (SellingItemNav != null)
|
||||
{
|
||||
answ = SellingItemNav.SourceType == ItemSourceType.Jwd || SellingItemNav.SourceType == ItemSourceType.FileBTL;
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -103,7 +99,7 @@ namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
}
|
||||
else if (SellingItemID > 0)
|
||||
{
|
||||
answ = SellingItemModel.ImgUrl(SellingItemID);
|
||||
answ = SellingItemModel.ImgUrl(SellingItemID ?? 0);
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
@@ -57,7 +58,7 @@ namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
/// <summary>
|
||||
/// ID dell'articolo di vendita Orderto
|
||||
/// </summary>
|
||||
public int SellingItemID { get; set; }
|
||||
public int? SellingItemID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Riferimento (opzionale9 al template da cui è derivato
|
||||
@@ -195,7 +196,7 @@ namespace EgwCoreLib.Lux.Data.DbModel.Sales
|
||||
else if (SellingItemID > 0)
|
||||
{
|
||||
//answ = $"SP.{SellingItemID:X12}";
|
||||
answ = SellingItemModel.ImgUrl(SellingItemID);
|
||||
answ = SellingItemModel.ImgUrl(SellingItemID ?? 0);
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Domains
|
||||
{
|
||||
public static class BomCalculator
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
public static List<BomItemDTO> GetBomList(string itemBOM)
|
||||
{
|
||||
List<BomItemDTO> answ = new List<BomItemDTO>();
|
||||
if (!string.IsNullOrEmpty(itemBOM) && itemBOM.Length > 2)
|
||||
{
|
||||
var bomList = JsonConvert.DeserializeObject<List<BomItemDTO>>(itemBOM);
|
||||
if (bomList != null)
|
||||
{
|
||||
answ = bomList;
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue completamento e la validazione dei dati BOM da lista articoli + gruppi,
|
||||
/// validando i dati stessi
|
||||
/// </summary>
|
||||
/// <param name="itemGroupList">Elenco ItemGroup da considerare</param>
|
||||
/// <param name="bomGenList">Item di tipo BOM/BomAlt AMMESSI</param>
|
||||
/// <param name="bomList">Lista BOM ricevuta da validare</param>
|
||||
/// <param name="bomList">Lista BOM precedente da confrontare x scelta alternativi</param>
|
||||
/// <param name="totCost">Costo netto componenti BOM calcolato</param>
|
||||
/// <param name="totPrice">Prezzo complessivo calcolato (con aggiunta marginalità)</param>
|
||||
/// <param name="totItemQty">Numero toale di item dello step BOM</param>
|
||||
/// <param name="numGroupOk">Controllo coerenza calcoli sui gruppi list2upd</param>
|
||||
/// <param name="numItemOk">Controllo coerenza calcoli su num list2upd</param>
|
||||
public static void Validate(
|
||||
List<ItemGroupModel> itemGroupList,
|
||||
List<ItemModel> bomGenList,
|
||||
ref List<BomItemDTO> bomList,
|
||||
List<BomItemDTO>? bomListPrev,
|
||||
ref double totCost,
|
||||
ref double totPrice,
|
||||
ref int totItemQty,
|
||||
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)
|
||||
{
|
||||
numGroupOk++;
|
||||
}
|
||||
|
||||
// 2025.09.16: se il prezzo arriva dalla BOM calcolata uso quello...
|
||||
if (item.Price > 0)
|
||||
{
|
||||
// resetto ItemID ma NON il prezzo
|
||||
item.ItemID = 0;
|
||||
// conto l'item
|
||||
numItemOk++;
|
||||
item.PriceEff = item.Price;
|
||||
// dovrei recuperare margine da BOM... da rivedere, x ora cablato 20%...
|
||||
margin = 0.2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*************************************************
|
||||
* Ricerca costo item:
|
||||
* - se ho un itemID --> cerco record ESATTO e sostituisco descrizioni & co...
|
||||
* - se non ho itemID --> cerco dati di selezione + qtyRange
|
||||
*************************************************/
|
||||
ItemModel? recCost = null;
|
||||
bool selExact = item.ItemID > 0;
|
||||
if (selExact)
|
||||
{
|
||||
recCost = bomGenList
|
||||
.Where(x => x.ItemID == item.ItemID)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
else
|
||||
{
|
||||
recCost = bomGenList
|
||||
.Where(x => x.CodGroup == item.ClassCode
|
||||
&& x.ItemIDParent == 0 // voglio NON sia un record CHILD
|
||||
&& x.ExtItemCode == item.ItemCode
|
||||
&& item.Qty >= x.QtyMin
|
||||
&& item.Qty < x.QtyMax)
|
||||
.OrderByDescending(x => x.Cost)
|
||||
.FirstOrDefault();
|
||||
// 2025.09.24: se ho un elenco item della BOM precedente
|
||||
if (bomListPrev != null && bomListPrev.Count > 0 && recCost != null)
|
||||
{
|
||||
// ...cerco item trovato come PARENT di altri item
|
||||
var listAlt = bomGenList.Where(x => x.ItemIDParent == recCost.ItemID).ToList();
|
||||
|
||||
// che cerco nella nella BOM precedente...
|
||||
var result = listAlt
|
||||
.Join(
|
||||
bomListPrev,
|
||||
l1 => l1.ItemID,
|
||||
l2 => l2.ItemID,
|
||||
(l1, l2) => l1)
|
||||
.ToList();
|
||||
// nel caso ne trovassi solo 1 uso quello al posto del recCost...
|
||||
if (result.Count == 1)
|
||||
{
|
||||
recCost = result.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// se trovato valorizzo!
|
||||
if (recCost != null)
|
||||
{
|
||||
numItemOk++;
|
||||
item.ItemID = recCost.ItemID;
|
||||
//item.PriceEff = recCost.BomCost * (1 + recCost.Margin);
|
||||
item.PriceEff = recCost.Cost;
|
||||
// se selezione esatta sovrascrivo altri valori
|
||||
if (selExact)
|
||||
{
|
||||
item.ItemCode = recCost.ExtItemCode;
|
||||
//item.DescriptionCode = recCost.Name;
|
||||
}
|
||||
margin = recCost.Margin;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.ItemID = 0;
|
||||
item.PriceEff = 0;
|
||||
}
|
||||
}
|
||||
// ...e aggiorno totale
|
||||
totCost += item.TotalCost;
|
||||
// e prezzo totale compreso margine
|
||||
totPrice += item.TotalCost * (1 + margin);
|
||||
totItemQty += item.ItemQty;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -48,13 +48,13 @@
|
||||
<PackageReference Include="NLog" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" />
|
||||
<PackageReference Include="RestSharp" />
|
||||
<PackageReference Include="Scrutor" />
|
||||
<PackageReference Include="StackExchange.Redis" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="DbModel\Engine\" />
|
||||
<Folder Include="Migrations\" />
|
||||
<Folder Include="Services\Internal\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
+4111
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,251 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class EnableSellItemNullable : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "SellingItemID",
|
||||
table: "sales_order_row",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "SellingItemID",
|
||||
table: "sales_offer_row",
|
||||
type: "int",
|
||||
nullable: true,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int");
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 1,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 18, 7, 36, 8, 630, DateTimeKind.Local).AddTicks(2026) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 2,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 18, 7, 36, 8, 630, DateTimeKind.Local).AddTicks(2044) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 3,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 18, 7, 36, 8, 630, DateTimeKind.Local).AddTicks(2051) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 4,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 17, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 18, 7, 36, 8, 630, DateTimeKind.Local).AddTicks(2057) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 1,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 2,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 3,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 4,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 5,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 6,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 7,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 8,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 9,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 10,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 18, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "SellingItemID",
|
||||
table: "sales_order_row",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.AlterColumn<int>(
|
||||
name: "SellingItemID",
|
||||
table: "sales_offer_row",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0,
|
||||
oldClrType: typeof(int),
|
||||
oldType: "int",
|
||||
oldNullable: true);
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 1,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 12, 5, 41, 29, 364, DateTimeKind.Local).AddTicks(1262) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 2,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 12, 5, 41, 29, 364, DateTimeKind.Local).AddTicks(1276) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 3,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 12, 5, 41, 29, 364, DateTimeKind.Local).AddTicks(1282) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer",
|
||||
keyColumn: "OfferID",
|
||||
keyValue: 4,
|
||||
columns: new[] { "DueDateProm", "DueDateReq", "ValidUntil" },
|
||||
values: new object[] { new DateTime(2026, 5, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 11, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 4, 12, 5, 41, 29, 364, DateTimeKind.Local).AddTicks(1289) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 1,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 2,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 3,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 4,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 5,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 6,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 7,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 8,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 9,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
|
||||
migrationBuilder.UpdateData(
|
||||
table: "sales_offer_row",
|
||||
keyColumn: "OfferRowID",
|
||||
keyValue: 10,
|
||||
columns: new[] { "Inserted", "Modified" },
|
||||
values: new object[] { new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local), new DateTime(2026, 3, 12, 0, 0, 0, 0, DateTimeKind.Local) });
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Stock;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Task;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
||||
@@ -1,14 +1,46 @@
|
||||
namespace EgwCoreLib.Lux.Data.Repository
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository
|
||||
{
|
||||
public abstract class BaseRepository : IBaseRepository
|
||||
{
|
||||
protected readonly DataLayerContext _dbCtx;
|
||||
protected BaseRepository(DataLayerContext db) => _dbCtx = db;
|
||||
#region Protected Fields
|
||||
|
||||
protected readonly IDbContextFactory<DataLayerContext> _ctxFactory;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Constructors
|
||||
|
||||
protected BaseRepository(IDbContextFactory<DataLayerContext> ctxFactory)
|
||||
=> _ctxFactory = ctxFactory;
|
||||
|
||||
#endregion Protected Constructors
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Creazione dbcontext per singola transazione
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task<DataLayerContext> CreateContextAsync()
|
||||
=> await _ctxFactory.CreateDbContextAsync();
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Salvataggio dati asincrono
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected async Task<bool> SaveChangesAsync(DataLayerContext ctx)
|
||||
=> await ctx.SaveChangesAsync() > 0;
|
||||
#endif
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#if false
|
||||
protected readonly DataLayerContext _dbCtx;
|
||||
protected BaseRepository(DataLayerContext db) => _dbCtx = db;
|
||||
public async Task<bool> SaveChangesAsync() => await _dbCtx.SaveChangesAsync() > 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public interface ITemplateRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(TemplateModel entity);
|
||||
|
||||
Task<bool> CloneAsync(TemplateModel rec2clone);
|
||||
|
||||
Task<int> CountChildrenAsync(int TemplateID);
|
||||
|
||||
Task<bool> DeleteAsync(TemplateModel entity);
|
||||
|
||||
Task<List<TemplateModel>> GetAllWithNavAsync();
|
||||
|
||||
Task<List<ItemModel>> GetBomItemsAsync();
|
||||
|
||||
Task<TemplateModel?> GetByIdAsync(int TemplateID);
|
||||
|
||||
Task<List<ItemGroupModel>> GetItemGroupsAsync();
|
||||
|
||||
Task<List<TemplateRowModel>> GetRowsAsync(int TemplateID);
|
||||
|
||||
Task<bool> SaveRowsAsync(List<TemplateRowModel> rows);
|
||||
|
||||
Task<bool> UpdateAsync(TemplateModel entity);
|
||||
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public interface ITemplateRowRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(TemplateRowModel entity);
|
||||
|
||||
Task<bool> CloneAsync(TemplateRowModel rec2clone);
|
||||
|
||||
Task<bool> DeleteAsync(TemplateRowModel entity);
|
||||
|
||||
Task<List<TemplateRowModel>> GetAllWithNavAsync();
|
||||
|
||||
Task<TemplateRowModel?> GetRowAsync(int templateRowId);
|
||||
|
||||
Task<List<TemplateRowModel>> GetRowsAsync(int templateId);
|
||||
|
||||
Task<bool> SaveRowsAsync(List<TemplateRowModel> rows);
|
||||
|
||||
Task<bool> UpdateAsync(TemplateRowModel entity);
|
||||
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public class TemplateRepository : BaseRepository, ITemplateRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public TemplateRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(TemplateModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetTemplate.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue il cloning completo di un Template e di TUTTE le relative righe...
|
||||
/// </summary>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CloneAsync(TemplateModel rec2clone)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
// 1. Recupero il record originale con i child
|
||||
var currRec = await dbCtx.DbSetTemplate
|
||||
.Include(x => x.TemplateRowNav)
|
||||
.FirstOrDefaultAsync(x => x.TemplateID == rec2clone.TemplateID);
|
||||
|
||||
if (currRec == null)
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Creo il nuovo parent
|
||||
var newRec = new TemplateModel
|
||||
{
|
||||
Name = rec2clone.Name,
|
||||
Envir = rec2clone.Envir,
|
||||
Description = rec2clone.Description,
|
||||
SourceType = rec2clone.SourceType,
|
||||
};
|
||||
|
||||
// 3. Clono i child
|
||||
newRec.TemplateRowNav = currRec.TemplateRowNav
|
||||
.Select(c => new TemplateRowModel
|
||||
{
|
||||
AwaitBom = c.AwaitBom,
|
||||
AwaitPrice = c.AwaitPrice,
|
||||
BomCost = c.BomCost,
|
||||
BomOk = c.BomOk,
|
||||
BomPrice = c.BomPrice,
|
||||
Envir = c.Envir,
|
||||
FileName = c.FileName,
|
||||
FileResource = c.FileResource,
|
||||
FileSize = c.FileSize,
|
||||
Inserted = now,
|
||||
ItemBOM = c.ItemBOM,
|
||||
ItemJCD = c.ItemJCD,
|
||||
ItemOk = c.ItemOk,
|
||||
ItemSteps = c.ItemSteps,
|
||||
ItemTags = c.ItemTags,
|
||||
JobID = c.JobID,
|
||||
Note = c.Note,
|
||||
ProdItemQty = c.ProdItemQty,
|
||||
Qty = c.Qty,
|
||||
RowNum = c.RowNum,
|
||||
SellingItemID = c.SellingItemID,
|
||||
SerStruct = c.SerStruct,
|
||||
StepCost = c.StepCost,
|
||||
StepFlowTime = c.StepFlowTime,
|
||||
StepLeadTime = c.StepLeadTime,
|
||||
StepPrice = c.StepPrice,
|
||||
Name = c.Name,
|
||||
TemplateRowUID = c.TemplateRowDtx
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 4. Aggiungo il nuovo parent (EF aggiunge anche i child)
|
||||
dbCtx.DbSetTemplate.Add(newRec);
|
||||
|
||||
// 5. Salvo tutto in transazione
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
await tx.CommitAsync();
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> CountChildrenAsync(int TemplateID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTemplateRow.CountAsync(x => x.TemplateID == TemplateID);
|
||||
}
|
||||
public async Task<bool> DeleteAsync(TemplateModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetTemplate.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<TemplateModel>> GetAllWithNavAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTemplate
|
||||
.Include(o => o.TemplateRowNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetBomItemsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => x.ItemType == ItemClassType.Bom || x.ItemType == ItemClassType.BomAlt)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<TemplateModel?> GetByIdAsync(int TemplateID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTemplate.FirstOrDefaultAsync(x => x.TemplateID == TemplateID);
|
||||
}
|
||||
|
||||
public async Task<List<ItemGroupModel>> GetItemGroupsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItemGroup.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<TemplateRowModel>> GetRowsAsync(int TemplateID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTemplateRow
|
||||
.Where(x => x.TemplateID == TemplateID)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveRowsAsync(List<TemplateRowModel> rows)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity when saving multiple rows
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
foreach (var row in rows)
|
||||
dbCtx.Entry(row).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
await tx.CommitAsync();
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(TemplateModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetTemplate.FirstOrDefaultAsync(x => x.TemplateID == entity.TemplateID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetTemplate.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public class TemplateRowRepository : BaseRepository, ITemplateRowRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public TemplateRowRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(TemplateRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetTemplateRow.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue il cloning completo di un Template e di TUTTE le relative righe...
|
||||
/// </summary>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CloneAsync(TemplateRowModel rec2clone)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var currRec = await dbCtx.DbSetTemplateRow
|
||||
.FirstOrDefaultAsync(x => x.TemplateRowID == rec2clone.TemplateRowID);
|
||||
|
||||
if (currRec == null)
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
return false;
|
||||
}
|
||||
|
||||
// cerco ultimo rec...
|
||||
var lastRec = await dbCtx
|
||||
.DbSetTemplateRow
|
||||
.Where(x => x.TemplateID == rec2clone.TemplateID)
|
||||
.OrderByDescending(x => x.RowNum)
|
||||
.FirstOrDefaultAsync();
|
||||
int rowNum = lastRec != null ? lastRec.RowNum + 1 : 1;
|
||||
|
||||
var newRec = new TemplateRowModel()
|
||||
{
|
||||
Name = rec2clone.Name,
|
||||
Envir = rec2clone.Envir,
|
||||
AwaitBom = rec2clone.AwaitBom,
|
||||
AwaitPrice = rec2clone.AwaitPrice,
|
||||
BomCost = rec2clone.BomCost,
|
||||
BomOk = rec2clone.BomOk,
|
||||
BomPrice = rec2clone.BomPrice,
|
||||
FileName = rec2clone.FileName,
|
||||
FileResource = rec2clone.FileResource,
|
||||
FileSize = rec2clone.FileSize,
|
||||
Inserted = rec2clone.Inserted,
|
||||
ItemBOM = rec2clone.ItemBOM,
|
||||
ItemJCD = rec2clone.ItemJCD,
|
||||
ItemOk = rec2clone.ItemOk,
|
||||
ItemSteps = rec2clone.ItemSteps,
|
||||
ItemTags = rec2clone.ItemTags,
|
||||
JobID = rec2clone.JobID,
|
||||
Note = rec2clone.Note,
|
||||
ProdItemQty = rec2clone.ProdItemQty,
|
||||
Qty = rec2clone.Qty,
|
||||
RowNum = rowNum,
|
||||
SellingItemID = rec2clone.SellingItemID,
|
||||
SellingItemNav = rec2clone.SellingItemNav,
|
||||
SerStruct = rec2clone.SerStruct,
|
||||
StepCost = rec2clone.StepCost,
|
||||
StepFlowTime = rec2clone.StepFlowTime,
|
||||
StepLeadTime = rec2clone.StepLeadTime,
|
||||
StepPrice = rec2clone.StepPrice,
|
||||
TemplateID = rec2clone.TemplateID,
|
||||
TemplateRowUID = rec2clone.TemplateRowDtx
|
||||
};
|
||||
|
||||
dbCtx.DbSetTemplateRow.Add(newRec);
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
await tx.CommitAsync();
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(TemplateRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetTemplateRow.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<TemplateRowModel>> GetAllWithNavAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTemplateRow
|
||||
.Include(o => o.SellingItemNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<TemplateRowModel?> GetRowAsync(int templateRowId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTemplateRow
|
||||
.FirstOrDefaultAsync(x => x.TemplateRowID == templateRowId);
|
||||
}
|
||||
|
||||
public async Task<List<TemplateRowModel>> GetRowsAsync(int templateId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTemplateRow
|
||||
.Where(x => x.TemplateID == templateId)
|
||||
.Include(r => r.SellingItemNav)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveRowsAsync(List<TemplateRowModel> rows)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity when saving multiple rows
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
foreach (var row in rows)
|
||||
dbCtx.Entry(row).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
await tx.CommitAsync();
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(TemplateRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetTemplateRow.FirstOrDefaultAsync(x => x.TemplateRowID == entity.TemplateRowID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetTemplateRow.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public class ConfGlassRepository : BaseRepository, IConfGlassRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ConfGlassRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(GlassModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetConfGlass.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(GlassModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetConfGlass.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<GlassModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetConfGlass.AsNoTracking().ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<GlassModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetConfGlass
|
||||
.Where(x => x.GlassID == recId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(GlassModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
var trackedEntity = await dbCtx.DbSetConfGlass.FirstOrDefaultAsync(x => x.GlassID == entity.GlassID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetConfGlass.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public class ConfProfileRepository : BaseRepository, IConfProfileRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ConfProfileRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(ProfileModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetConfProfile.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> AddRangeAsync(List<ProfileModel> entityList)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetConfProfile.AddRangeAsync(entityList);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(ProfileModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetConfProfile.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
public async Task<List<ProfileModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetConfProfile.AsNoTracking().ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ProfileModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetConfProfile
|
||||
.FirstOrDefaultAsync(x => x.ProfileID == recId);
|
||||
}
|
||||
public async Task<ProfileModel?> GetByUidAsync(string uID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetConfProfile
|
||||
.FirstOrDefaultAsync(x => x.Code == uID);
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> UpdateAsync(ProfileModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
var trackedEntity = await dbCtx.DbSetConfProfile.FirstOrDefaultAsync(x => x.ProfileID == entity.ProfileID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetConfProfile.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public class ConfWoodRepository : BaseRepository, IConfWoodRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ConfWoodRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(WoodModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetConfWood.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(WoodModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetConfWood.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<WoodModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetConfWood
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<WoodModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetConfWood
|
||||
.Where(x => x.WoodID == recId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(WoodModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
var trackedEntity = await dbCtx.DbSetConfWood.FirstOrDefaultAsync(x => x.WoodID == entity.WoodID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetConfWood.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public class EnvirParamRepository : BaseRepository, IEnvirParamRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public EnvirParamRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<EnvirParamModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetEnvirPar
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public interface IConfGlassRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(GlassModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(GlassModel entity);
|
||||
|
||||
Task<List<GlassModel>> GetAllAsync();
|
||||
|
||||
Task<GlassModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<bool> UpdateAsync(GlassModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public interface IConfProfileRepository : IBaseRepository
|
||||
{
|
||||
Task<bool> AddAsync(ProfileModel entity);
|
||||
|
||||
Task<bool> AddRangeAsync(List<ProfileModel> entityList);
|
||||
|
||||
Task<bool> DeleteAsync(ProfileModel entity);
|
||||
|
||||
Task<List<ProfileModel>> GetAllAsync();
|
||||
|
||||
Task<ProfileModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<ProfileModel?> GetByUidAsync(string uID);
|
||||
|
||||
Task<bool> UpdateAsync(ProfileModel entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public interface IConfWoodRepository : IBaseRepository
|
||||
{
|
||||
Task<bool> AddAsync(WoodModel entity);
|
||||
|
||||
|
||||
Task<bool> DeleteAsync(WoodModel entity);
|
||||
|
||||
Task<List<WoodModel>> GetAllAsync();
|
||||
|
||||
Task<WoodModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<bool> UpdateAsync(WoodModel entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Config
|
||||
{
|
||||
public interface IEnvirParamRepository
|
||||
{
|
||||
Task<List<EnvirParamModel>> GetAllAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Cost
|
||||
{
|
||||
public class CostDriverRepository : BaseRepository, ICostDriverRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public CostDriverRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<CostDriverModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetCostDriver
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Cost
|
||||
{
|
||||
public interface ICostDriverRepository
|
||||
{
|
||||
Task<List<CostDriverModel>> GetAllAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Cost
|
||||
{
|
||||
public interface IResourceRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(ResourceModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(ResourceModel entity);
|
||||
|
||||
Task<List<ResourceModel>> GetAllAsync();
|
||||
|
||||
Task<ResourceModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<bool> UpdateAsync(ResourceModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Cost;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Cost
|
||||
{
|
||||
public class ResourceRepository : BaseRepository, IResourceRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ResourceRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(ResourceModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetResource.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(ResourceModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetResource.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<ResourceModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetResource
|
||||
.Include(d => d.DriverNav)
|
||||
.Include(j => j.JobStepNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<ResourceModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetResource.FirstOrDefaultAsync(x => x.ResourceID == recId);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(ResourceModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetResource.FirstOrDefaultAsync(x => x.ResourceID == entity.ResourceID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetResource.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
{
|
||||
public interface IBaseRepository
|
||||
{
|
||||
Task<bool> SaveChangesAsync();
|
||||
//Task<DataLayerContext> CreateContextAsync();
|
||||
//Task<bool> SaveChangesAsync(DataLayerContext ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Items
|
||||
{
|
||||
public interface IItemGroupRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddMissingAsync(List<BomItemDTO> bomList);
|
||||
|
||||
Task<bool> AddRangeAsync(List<ItemGroupModel> entityList);
|
||||
|
||||
Task<List<ItemGroupModel>> GetAllAsync();
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Items
|
||||
{
|
||||
public interface IItemRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(ItemModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(ItemModel entity);
|
||||
|
||||
Task<ItemModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<List<ItemModel>> GetAltAsync(int recId);
|
||||
|
||||
Task<List<ItemModel>> GetFiltAsync(string CodGroup, ItemClassType ItemType);
|
||||
|
||||
Task<List<ItemModel>> GetSearchAsync(string term);
|
||||
|
||||
Task<bool> MassUpdateAsync(List<BomItemDTO> list2upd, double setCost, double defMargin, double defQtyMax, string defUM, int roundVal = 0, double scaleFactor = 1_000_000.0);
|
||||
|
||||
Task<bool> UpdateAsync(ItemModel entity);
|
||||
|
||||
Task<bool> UpsertFromBomAsync(List<BomItemDTO> bomList);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Items
|
||||
{
|
||||
public interface ISellingItemRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(SellingItemModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(SellingItemModel entity);
|
||||
|
||||
Task<SellingItemModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<List<SellingItemModel>> GetByEnvirAsync(EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir);
|
||||
|
||||
Task<List<SellingItemModel>> GetFiltAsync(EgwMultiEngineManager.Data.Constants.EXECENVIRONMENTS envir, ItemSourceType sourceType);
|
||||
|
||||
Task<bool> UpdateAsync(SellingItemModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Items
|
||||
{
|
||||
public class ItemGroupRepository : BaseRepository, IItemGroupRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ItemGroupRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddMissingAsync(List<BomItemDTO> bomList)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
bool fatto = false;
|
||||
// recupero lista esistenti
|
||||
var itemGroupList = await dbCtx.DbSetItemGroup
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
|
||||
// calcolo i distinct dei CodGroup x eventuale insert preventivo
|
||||
List<string> distCodGroups = bomList
|
||||
.Select(i => i.ClassCode)
|
||||
.Distinct()
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c))
|
||||
.ToList();
|
||||
|
||||
// elenco da inserire...
|
||||
var codGroupsToInsert = distCodGroups
|
||||
.Where(x => !itemGroupList.Any(i => i.CodGroup == x))
|
||||
.Select(x => new ItemGroupModel() { CodGroup = x, Description = x })
|
||||
.ToList();
|
||||
// se ci sono inserisco!
|
||||
if (codGroupsToInsert != null && codGroupsToInsert.Count > 0)
|
||||
{
|
||||
await dbCtx
|
||||
.DbSetItemGroup
|
||||
.AddRangeAsync(codGroupsToInsert);
|
||||
|
||||
// e salvo
|
||||
fatto = await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
public async Task<bool> AddRangeAsync(List<ItemGroupModel> entityList)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetItemGroup.AddRangeAsync(entityList);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<ItemGroupModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItemGroup
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using System.Globalization;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Items
|
||||
{
|
||||
public class ItemRepository : BaseRepository, IItemRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ItemRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(ItemModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetItem.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(ItemModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetItem.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetAltAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
List<ItemModel> dbResult = new List<ItemModel>();
|
||||
// cerco singolo record x partire...
|
||||
var currRec = dbCtx
|
||||
.DbSetItem
|
||||
.Where(x => x.ItemID == recId)
|
||||
.FirstOrDefault();
|
||||
|
||||
if ((currRec != null))
|
||||
{
|
||||
// se è un record che ha parentId > 0 --> cerco da quello record analoghi + parent
|
||||
if (currRec.ItemIDParent > 0)
|
||||
{
|
||||
dbResult = await dbCtx
|
||||
.DbSetItem
|
||||
.Where(x => x.ItemID == currRec.ItemIDParent || x.ItemIDParent == currRec.ItemIDParent)
|
||||
.ToListAsync();
|
||||
}
|
||||
// altrimenti cerco child collegati
|
||||
else
|
||||
{
|
||||
dbResult = await dbCtx
|
||||
.DbSetItem
|
||||
.Where(x => x.ItemID == currRec.ItemID || x.ItemIDParent == currRec.ItemID)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
public async Task<ItemModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => x.ItemID == recId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetFiltAsync(string CodGroup, ItemClassType ItemType)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => (string.IsNullOrEmpty(CodGroup) || x.CodGroup == CodGroup) && (ItemType == ItemClassType.ND || x.ItemType == ItemType))
|
||||
.AsNoTracking()
|
||||
.Include(g => g.ItemGroupNav)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetSearchAsync(string term)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => x.Description.Contains(term, StringComparison.InvariantCultureIgnoreCase) || x.ExtItemCode.Contains(term, StringComparison.InvariantCultureIgnoreCase) || x.SupplCode.Contains(term, StringComparison.InvariantCultureIgnoreCase))
|
||||
.AsNoTracking()
|
||||
//.Include(g => g.ItemGroupNav)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> MassUpdateAsync(List<BomItemDTO> list2upd, double setCost, double defMargin, double defQtyMax, string defUM, int roundVal = 0, double scaleFactor = 1_000_000.0)
|
||||
{
|
||||
bool answ = false;
|
||||
if (list2upd == null || !list2upd.Any())
|
||||
return answ;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Validate input
|
||||
if (setCost <= 0)
|
||||
throw new ArgumentException("setCost must be greater than 0.");
|
||||
|
||||
// Step 1: Extract width and height from ExtItemCode
|
||||
var itemUpdates = new List<ItemModel>();
|
||||
|
||||
foreach (var item in list2upd)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item.ItemCode))
|
||||
continue;
|
||||
|
||||
// Try to parse ExtItemCode: "Pine-200.0x360.0"
|
||||
if (!item.ItemCode.Contains("-") || !item.ItemCode.Contains("x"))
|
||||
{
|
||||
// Skip invalid format
|
||||
continue;
|
||||
}
|
||||
|
||||
// Split by "-" to get prefix and number part
|
||||
var parts = item.ItemCode.Split('-', 2);
|
||||
if (parts.Length < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string numberPart = parts[1]; // e.g. "200.0x360.0"
|
||||
|
||||
// Split by "x" to get width and height
|
||||
var widthHeight = numberPart.Split('x', 2);
|
||||
if (widthHeight.Length < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!double.TryParse(widthHeight[0], NumberStyles.Any, CultureInfo.InvariantCulture, out double width) ||
|
||||
!double.TryParse(widthHeight[1], NumberStyles.Any, CultureInfo.InvariantCulture, out double height))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Step 2: Calculate Cost using formula:
|
||||
// Cost = setCost / 1,000,000 * width * height
|
||||
double calculatedCost = (setCost / scaleFactor) * width * height;
|
||||
// if requested do round ceiling
|
||||
if (roundVal > 0)
|
||||
{
|
||||
calculatedCost = Math.Ceiling(calculatedCost / roundVal) * roundVal;
|
||||
}
|
||||
|
||||
// Optional: you can also apply margin to cost if needed, but you said "Cost = ..."
|
||||
// So we're just computing it based on width/height
|
||||
|
||||
// Step 4: Create a new ItemModel with updated values
|
||||
var updatedItem = new ItemModel
|
||||
{
|
||||
ItemID = item.ItemID,
|
||||
ExtItemCode = item.ItemCode, // keep original
|
||||
Cost = calculatedCost,
|
||||
Margin = defMargin,
|
||||
QtyMax = defQtyMax,
|
||||
UM = defUM
|
||||
};
|
||||
|
||||
itemUpdates.Add(updatedItem);
|
||||
}
|
||||
|
||||
// Step 5: Update database using EF Core (EF Core doesn't support "update" on entire list directly)
|
||||
// We'll use .UpdateRange() or a raw update via .Where() and .SetProperty()
|
||||
|
||||
// ✅ Use EF Core's Update method (for bulk update)
|
||||
if (itemUpdates.Any())
|
||||
{
|
||||
// Update only the ones that exist in the DB
|
||||
var existingItems = await dbCtx.DbSetItem
|
||||
.Where(i => itemUpdates.Select(ui => ui.ItemID).Contains(i.ItemID))
|
||||
.ToListAsync();
|
||||
|
||||
if (existingItems.Any())
|
||||
{
|
||||
// Update existing records using EF Core's Update method
|
||||
foreach (var updatedItem in itemUpdates)
|
||||
{
|
||||
var existing = existingItems.FirstOrDefault(i => i.ItemID == updatedItem.ItemID);
|
||||
if (existing != null)
|
||||
{
|
||||
// Update only the fields we're setting
|
||||
existing.Cost = updatedItem.Cost;
|
||||
existing.Margin = updatedItem.Margin;
|
||||
existing.QtyMax = updatedItem.QtyMax;
|
||||
}
|
||||
}
|
||||
|
||||
answ = await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(ItemModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetItem.FirstOrDefaultAsync(x => x.ItemID == entity.ItemID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetItem.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> UpsertFromBomAsync(List<BomItemDTO> bomList)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// prendo solo elementi a prezzo 0 da salvare sul DB
|
||||
var item2save = bomList
|
||||
.Where(x => x.Price == 0)
|
||||
.ToList();
|
||||
List<ItemModel> listInserted = new List<ItemModel>();
|
||||
|
||||
// ciclo x ogni elemento della BOM, cercando x gruppo e ExtItemCode
|
||||
foreach (var item in item2save)
|
||||
{
|
||||
var currRec = dbCtx
|
||||
.DbSetItem
|
||||
.Where(x => x.CodGroup == item.ClassCode && x.ExtItemCode == item.ItemCode)
|
||||
.FirstOrDefault();
|
||||
|
||||
// se nullo --> verifico x inserire!!!
|
||||
if (currRec == null)
|
||||
{
|
||||
// verifico NON sia tra gli list2upd già in fase di inserimento
|
||||
if (!listInserted.Any(x => x.CodGroup == item.ClassCode && x.ExtItemCode == item.ItemCode))
|
||||
{
|
||||
ItemModel newRec = new ItemModel()
|
||||
{
|
||||
CodGroup = item.ClassCode,
|
||||
ItemType = Core.Enums.ItemClassType.Bom,
|
||||
IsService = false,
|
||||
// da calcolare meglio x gruppo
|
||||
ItemCode = 0,
|
||||
ExtItemCode = item.ItemCode,
|
||||
SupplCode = "BOM ITEM",
|
||||
Description = $"BOM | {item.ClassCode} | {item.ItemCode}",
|
||||
Cost = 0,
|
||||
Margin = 0,
|
||||
QtyMin = 0,
|
||||
QtyMax = 0,
|
||||
UM = "#"
|
||||
};
|
||||
dbCtx.DbSetItem.Add(newRec);
|
||||
listInserted.Add(newRec);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
await tx.CommitAsync();
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwMultiEngineManager.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Items
|
||||
{
|
||||
public class SellingItemRepository : BaseRepository, ISellingItemRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public SellingItemRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(SellingItemModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetSellItem.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(SellingItemModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetSellItem.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<SellingItemModel>> GetByEnvirAsync(Constants.EXECENVIRONMENTS envir)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetSellItem
|
||||
.Where(x => x.Envir == envir)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<SellingItemModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetSellItem
|
||||
.Where(x => x.SellingItemID == recId)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<List<SellingItemModel>> GetFiltAsync(Constants.EXECENVIRONMENTS envir, ItemSourceType sourceType)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetSellItem
|
||||
.Where(x => (x.Envir == envir || envir == Constants.EXECENVIRONMENTS.NULL) && (sourceType == ItemSourceType.ND || x.SourceType == sourceType))
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(SellingItemModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetSellItem.FirstOrDefaultAsync(x => x.SellingItemID == entity.SellingItemID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetSellItem.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Job
|
||||
{
|
||||
public interface IJobStepRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(JobStepModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(JobStepModel entity);
|
||||
|
||||
Task<JobStepModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<List<JobStepModel>> GetByParentAsync(int jobID);
|
||||
|
||||
Task<bool> MoveAsync(JobStepModel selRec, bool moveUp);
|
||||
|
||||
Task<bool> UpdateAsync(JobStepModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Job
|
||||
{
|
||||
public interface IJobTaskRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(JobTaskModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(JobTaskModel entity);
|
||||
|
||||
Task<List<JobTaskModel>> GetAllAsync();
|
||||
|
||||
Task<JobTaskModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<bool> MergeTagsAsync(int JobID, List<string> reqTagList);
|
||||
|
||||
Task<bool> MoveAsync(JobTaskModel selRec, bool moveUp);
|
||||
|
||||
Task<bool> UpdateAsync(JobTaskModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Job
|
||||
{
|
||||
public interface IPhaseRepository
|
||||
{
|
||||
Task<List<PhaseModel>> GetAllAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Job
|
||||
{
|
||||
public class JobStepRepository : BaseRepository, IJobStepRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public JobStepRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(JobStepModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetJobStep.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(JobStepModel rec2del)
|
||||
{
|
||||
// Add validation for null entity
|
||||
if (rec2del == null) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (multi-row update + delete)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var dbResult = await dbCtx.DbSetJobStep
|
||||
.FirstOrDefaultAsync(x => x.JobStepID == rec2del.JobStepID);
|
||||
|
||||
if (dbResult == null)
|
||||
return false;
|
||||
|
||||
var list2Move = await dbCtx.DbSetJobStep
|
||||
.Where(x => x.JobID == rec2del.JobID && x.Index > dbResult.Index)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in list2Move)
|
||||
{
|
||||
item.Index--;
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
dbCtx.DbSetJobStep.Remove(dbResult);
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<JobStepModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetJobStep.FirstOrDefaultAsync(x => x.JobStepID == recId);
|
||||
}
|
||||
|
||||
public async Task<List<JobStepModel>> GetByParentAsync(int jobID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetJobStep
|
||||
.Where(x => x.JobID == jobID)
|
||||
.Include(c => c.JobNav)
|
||||
.Include(c => c.PhaseNav)
|
||||
.Include(c => c.ResourceNav)
|
||||
.Include(c => c.TagNav)
|
||||
.Include(c => c.ResourceNav.DriverNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> MoveAsync(JobStepModel selRec, bool moveUp)
|
||||
{
|
||||
// Add validation for null entity
|
||||
if (selRec == null) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (multi-row update)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var currRec = await dbCtx.DbSetJobStep
|
||||
.FirstOrDefaultAsync(x => x.JobStepID == selRec.JobStepID);
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
int numRec = await dbCtx.DbSetJobStep
|
||||
.CountAsync(x => x.JobID == selRec.JobID);
|
||||
|
||||
int newPos = moveUp ? currRec.Index - 1 : currRec.Index + 1;
|
||||
|
||||
bool canMove = moveUp ? newPos > 0 : newPos <= numRec;
|
||||
if (!canMove)
|
||||
return false;
|
||||
|
||||
var otherRec = await dbCtx.DbSetJobStep
|
||||
.FirstOrDefaultAsync(x => x.JobID == selRec.JobID && x.Index == newPos);
|
||||
|
||||
if (otherRec == null)
|
||||
return false;
|
||||
|
||||
otherRec.Index = currRec.Index;
|
||||
currRec.Index = newPos;
|
||||
|
||||
dbCtx.Entry(otherRec).State = EntityState.Modified;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(JobStepModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
var trackedEntity = await dbCtx.DbSetJobStep.FirstOrDefaultAsync(x => x.JobStepID == entity.JobStepID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetJobStep.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Job
|
||||
{
|
||||
public class JobTaskRepository : BaseRepository, IJobTaskRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public JobTaskRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(JobTaskModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetJobTask.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(JobTaskModel rec2del)
|
||||
{
|
||||
// Add validation for null entity
|
||||
if (rec2del == null) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (multi-row update + delete)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var dbResult = await dbCtx.DbSetJobTask
|
||||
.FirstOrDefaultAsync(x => x.JobID == rec2del.JobID);
|
||||
|
||||
if (dbResult == null)
|
||||
return false;
|
||||
|
||||
var list2Move = await dbCtx.DbSetJobTask
|
||||
.Where(x => x.JobID == rec2del.JobID && x.Index > dbResult.Index)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in list2Move)
|
||||
{
|
||||
item.Index--;
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
dbCtx.DbSetJobTask.Remove(dbResult);
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<JobTaskModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetJobTask
|
||||
.Include(c => c.TagNav)
|
||||
.Include(c => c.JobStepNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<JobTaskModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetJobTask.FirstOrDefaultAsync(x => x.JobID == recId);
|
||||
}
|
||||
|
||||
public async Task<bool> MergeTagsAsync(int JobID, List<string> reqTagList)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (multi-row add + multi-row remove)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var currRec = await dbCtx.DbSetJobTask
|
||||
.Where(x => x.JobID == JobID)
|
||||
.Include(t => t.TagNav)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
var currentTags = currRec.TagNav.Select(t => t.CodTag).ToList();
|
||||
|
||||
// calcolo modifiche
|
||||
var toAdd = reqTagList.Except(currentTags).ToList();
|
||||
var toRemove = currentTags.Except(reqTagList).ToList();
|
||||
|
||||
// aggiunte
|
||||
foreach (var tag in toAdd)
|
||||
{
|
||||
currRec.TagNav.Add(new JobTaskTagModel
|
||||
{
|
||||
JobID = JobID,
|
||||
CodTag = tag
|
||||
});
|
||||
}
|
||||
// rimozioni
|
||||
foreach (var tag in toRemove)
|
||||
{
|
||||
var entity = currRec.TagNav.FirstOrDefault(t => t.CodTag == tag);
|
||||
if (entity != null)
|
||||
dbCtx.Remove(entity);
|
||||
}
|
||||
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> MoveAsync(JobTaskModel selRec, bool moveUp)
|
||||
{
|
||||
// Add validation for null entity
|
||||
if (selRec == null) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (multi-row update)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var currRec = await dbCtx.DbSetJobTask
|
||||
.FirstOrDefaultAsync(x => x.JobID == selRec.JobID);
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
int numRec = await dbCtx.DbSetJobTask
|
||||
.CountAsync();
|
||||
|
||||
int newPos = moveUp ? currRec.Index - 1 : currRec.Index + 1;
|
||||
|
||||
bool canMove = moveUp ? newPos > 0 : newPos <= numRec;
|
||||
if (!canMove)
|
||||
return false;
|
||||
|
||||
var otherRec = await dbCtx.DbSetJobTask
|
||||
.FirstOrDefaultAsync(x => x.JobID == selRec.JobID && x.Index == newPos);
|
||||
|
||||
if (otherRec == null)
|
||||
return false;
|
||||
|
||||
otherRec.Index = currRec.Index;
|
||||
currRec.Index = newPos;
|
||||
|
||||
dbCtx.Entry(otherRec).State = EntityState.Modified;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(JobTaskModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
var trackedEntity = await dbCtx.DbSetJobTask.FirstOrDefaultAsync(x => x.JobID == entity.JobID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetJobTask.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Job;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Job
|
||||
{
|
||||
public class PhaseRepository : BaseRepository, IPhaseRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public PhaseRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<PhaseModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetPhase
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public interface IProductionBatchRepository
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Creazione di un Batch con relativo Tag e info x creazione ODL correlati
|
||||
/// </summary>
|
||||
/// <param name="newRec"></param>
|
||||
/// <returns></returns>
|
||||
Task<ProductionBatchModel?> CreateAsync(ProductionBatchModel entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public interface IProductionGroupRepository
|
||||
{
|
||||
Task<List<ProductionGroupModel>> GetByOrderRowAsync(int orderRowID);
|
||||
|
||||
Task<List<ProductionGroupModel>> GetByOrderStateAsync(OrderStates reqState);
|
||||
|
||||
Task<bool> UpsertBalanceAsync(string uID, string rGroup, string rawBalance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public interface IProductionItemRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<int> BulkAssignProdBatchAsync(int orderRowId, int prodBatchId);
|
||||
|
||||
Task<int> BulkAssignProdGroupAsync(int OrderRowId, int ProdGroupId, Dictionary<string, double> itemsToAssign);
|
||||
|
||||
Task<List<ProductionItemModel>> GetByOrderRowAsync(int orderRowId);
|
||||
|
||||
Task<int> ResetAssignAsync(int orderRowID);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using EgwCoreLib.Lux.Core.Generic;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public interface IProductionOdlRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Metodo aggiunta record
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> AddAsync(ProductionODLModel entity);
|
||||
|
||||
Task<int> AssignProdItem2OdlAsync(List<ProductionODLModel> dbList, Dictionary<(int phaseId, int resId, string machine, int index), List<string>> dictParts);
|
||||
|
||||
/// <summary>
|
||||
/// Insert sul DB di un elenco ODL con calcolo della relativa KEY a cui poter, successivamente, collegare i record child (items)
|
||||
/// </summary>
|
||||
/// <param name="listOdl2ins"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
Task<List<ProductionODLModel>> CreateAsync(List<ProductionODLModel> listOdl2ins);
|
||||
|
||||
/// <summary>
|
||||
/// Recupero record ProdOdl dato Tag/uID
|
||||
/// </summary>
|
||||
/// <param name="uID"></param>
|
||||
/// <returns></returns>
|
||||
Task<ProductionODLModel?> GetByUidAsync(string uID);
|
||||
|
||||
/// <summary>
|
||||
/// Elenco PODL non assegnati
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<ProductionODLModel>> GetUnassignAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Elenco PODL non assegnati con struttura DTO appiattita
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<List<OdlAssignDto>> GetUnassignOdlDtoAsync();
|
||||
|
||||
/// <summary>
|
||||
/// Update generico record
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
Task<bool> UpdateAsync(ProductionODLModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public interface IProductionPlantRepository
|
||||
{
|
||||
Task<List<ProductionPlantModel>> GetAllAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MySqlConnector;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public class ProductionBatchRepository : BaseRepository, IProductionBatchRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ProductionBatchRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Creazione di un Batch con relativo Tag e info x creazione ODL correlati
|
||||
/// </summary>
|
||||
/// <param name="newRec"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ProductionBatchModel?> CreateAsync(ProductionBatchModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Definiamo i parametri di input
|
||||
var pDesc = new MySqlParameter("@pDescription", entity.Description ?? (object)DBNull.Value);
|
||||
var pDate = new MySqlParameter("@pDueDate", entity.DueDate);
|
||||
var pPref = new MySqlParameter("@pPrefix", "BC.");
|
||||
var pYear = new MySqlParameter("@pYear", entity.DueDate.Year);
|
||||
var pEnv = new MySqlParameter("@pEnv", entity.Envir);
|
||||
|
||||
// Eseguiamo la procedura e mappiamo il risultato direttamente sul modello
|
||||
// Nota: DbSetProdBatch deve essere configurato nel DbContext
|
||||
var dbResult = await dbCtx
|
||||
.DbSetProdBatch
|
||||
.FromSqlRaw("CALL stp_ProdBatch_insert(@pDescription, @pDueDate, @pPrefix, @pYear, @pEnv)", pDesc, pDate, pPref, pYear, pEnv)
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
return dbResult;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using EgwCoreLib.Lux.Core.Generic;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public class ProductionGroupRepository : BaseRepository, IProductionGroupRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ProductionGroupRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Elenco record ProductionGroup dato OrderRow
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ProductionGroupModel>> GetByOrderRowAsync(int orderRowID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetProdGroup
|
||||
.AsNoTracking()
|
||||
.Where(x => x.OrderRowID == orderRowID)
|
||||
.Include(i => i.ItemsNav)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco record ProductionGroup dato Stato dell'OrderRow
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ProductionGroupModel>> GetByOrderStateAsync(OrderStates reqState)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetProdGroup
|
||||
.AsNoTracking()
|
||||
.Include(o => o.OrderRowNav)
|
||||
.Where(x => x.OrderRowNav.OrderRowState == reqState)
|
||||
.Include(i => i.ItemsNav)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add record di un singolo ProdGroup da fase Balance
|
||||
/// </summary>
|
||||
/// <param name="uID">UID dell'item offerta di cui si è ricevuto l'oggetto Balance'</param>
|
||||
/// <param name="rGroup">Prod Group di riferimento</param>
|
||||
/// <param name="rawBalance"></param>
|
||||
public async Task<bool> UpsertBalanceAsync(string uID, string rGroup, string rawBalance)
|
||||
{
|
||||
bool answ = false;
|
||||
// Add validation for null or empty list
|
||||
if (string.IsNullOrWhiteSpace(uID) ||
|
||||
string.IsNullOrWhiteSpace(rGroup) ||
|
||||
string.IsNullOrWhiteSpace(rawBalance))
|
||||
{
|
||||
return answ;
|
||||
}
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// Tentativo di deserializzazione
|
||||
var data = JsonConvert.DeserializeObject<Dictionary<string, ProdMachineDetailDto>>(rawBalance);
|
||||
// proseguo solo se è valida la deserializzazione...
|
||||
if (data != null)
|
||||
{
|
||||
// Togliamo la 'G' e convertiamo in int (gestisce automaticamente "01" -> 1)
|
||||
int grpIdx = int.Parse(rGroup.TrimStart('G'));
|
||||
// recupero ord row (parent)...
|
||||
var ordRowRec = dbCtx
|
||||
.DbSetOrderRow
|
||||
.Where(x => x.OrderRowUID == uID)
|
||||
.FirstOrDefault();
|
||||
if (ordRowRec != null)
|
||||
{
|
||||
// recupero record specifico
|
||||
var currRec = dbCtx
|
||||
.DbSetProdGroup
|
||||
.Where(x => x.OrderRowID == ordRowRec.OrderRowID && x.GrpIdx == grpIdx)
|
||||
.FirstOrDefault();
|
||||
|
||||
// se trovato aggiorno
|
||||
if (currRec != null)
|
||||
{
|
||||
currRec.WorkGroupListRaw = rawBalance;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
}
|
||||
// altrimenti aggiungo
|
||||
else
|
||||
{
|
||||
ProductionGroupModel newRec = new ProductionGroupModel()
|
||||
{
|
||||
OrderRowID = ordRowRec.OrderRowID,
|
||||
GrpIdx = grpIdx,
|
||||
WorkGroupListRaw = rawBalance
|
||||
};
|
||||
dbCtx
|
||||
.DbSetProdGroup
|
||||
.Add(newRec);
|
||||
}
|
||||
|
||||
// segno ordine come Assigned se non lo fosse...
|
||||
if (ordRowRec.OrderRowState != OrderStates.Assigned)
|
||||
{
|
||||
ordRowRec.OrderRowState = OrderStates.Assigned;
|
||||
dbCtx.Entry(ordRowRec).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
// salvo TUTTI i cambiamenti...
|
||||
answ = await dbCtx.SaveChangesAsync() > 0;
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public class ProductionItemRepository : BaseRepository, IProductionItemRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ProductionItemRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Esegue assegnazione bulk dei ProdItem ad un unico ProdBatch parent (per ora totale x RigaOrd)
|
||||
/// </summary>
|
||||
/// <param name="orderRowId"></param>
|
||||
/// <param name="prodBatchId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> BulkAssignProdBatchAsync(int orderRowId, int prodBatchId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
int totUpd = 0;
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
int rowsAffected = await dbCtx.DbSetProdItem
|
||||
.Where(p => p.OrderRowID == orderRowId)
|
||||
.ExecuteUpdateAsync(setters => setters
|
||||
.SetProperty(p => p.ProdBatchID, prodBatchId)
|
||||
);
|
||||
|
||||
totUpd += rowsAffected;
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
return totUpd;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue assegnazione bulk dei ProdItem ad un unico ProdGroup parent
|
||||
/// </summary>
|
||||
/// <param name="orderRowId"></param>
|
||||
/// <param name="prodGroupId"></param>
|
||||
/// <param name="itemsToAssign"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> BulkAssignProdGroupAsync(int orderRowId, int prodGroupId, Dictionary<string, double> itemsToAssign)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
int totUpd = 0;
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
foreach (var entry in itemsToAssign)
|
||||
{
|
||||
int rowsAffected = await dbCtx.DbSetProdItem
|
||||
.Where(p => p.OrderRowID == orderRowId && p.ProdItemTag == entry.Key)
|
||||
.ExecuteUpdateAsync(setters => setters
|
||||
.SetProperty(p => p.ProdGroupID, prodGroupId)
|
||||
.SetProperty(p => p.EstimTime, entry.Value)
|
||||
);
|
||||
|
||||
totUpd += rowsAffected;
|
||||
}
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
return totUpd;
|
||||
}
|
||||
|
||||
public async Task<List<ProductionItemModel>> GetByOrderRowAsync(int orderRowId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetProdItem
|
||||
.AsNoTracking()
|
||||
.Where(x => x.OrderRowID == orderRowId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<int> ResetAssignAsync(int orderRowID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
int numItem = 0;
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
numItem = await dbCtx.DbSetProdItem
|
||||
.Where(p => p.OrderRowID == orderRowID)
|
||||
.ExecuteUpdateAsync(setters => setters
|
||||
.SetProperty(p => p.ProdGroupID, (int?)null)
|
||||
.SetProperty(p => p.EstimTime, 0)
|
||||
);
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
return numItem;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
using EgwCoreLib.Lux.Core.Generic;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MySqlConnector;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public class ProductionOdlRepository : BaseRepository, IProductionOdlRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ProductionOdlRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(ProductionODLModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetProdODL.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assegnazione in blocco degli item agli ODL corrispondenti
|
||||
/// </summary>
|
||||
/// <param name="dbList"></param>
|
||||
/// <param name="dictParts"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> AssignProdItem2OdlAsync(List<ProductionODLModel> dbList, Dictionary<(int phaseId, int resId, string machine, int index), List<string>> dictParts)
|
||||
{
|
||||
int totalCreated = 0;
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// 1. Recuperiamo tutti i ProdBatchID coinvolti per fare una sola query
|
||||
List<int> batchIds = dbList.Select(o => o.ProdBatchID).Distinct().ToList();
|
||||
|
||||
if (batchIds != null && batchIds.Count > 0)
|
||||
{
|
||||
// 2. Carichiamo in memoria i ProdItem necessari (solo ID e Tag per risparmiare RAM)
|
||||
var itemsList = await dbCtx.DbSetProdItem
|
||||
.Where(x => batchIds.Contains(x.ProdBatchID ?? 0) && x.ProdItemTag != null && x.ProdItemTag != "")
|
||||
.Select(x => new { x.ProdItemID, x.ProdItemTag })
|
||||
.ToListAsync();
|
||||
|
||||
// 1. Usiamo il "!" (null-forgiving operator) dopo x.ProdItemTag
|
||||
// perché il filtro .Where sopra garantisce che non sia null.
|
||||
var itemLookup = itemsList
|
||||
.GroupBy(x => x.ProdItemTag!)
|
||||
.ToDictionary(
|
||||
g => g.Key,
|
||||
g => g.First().ProdItemID,
|
||||
StringComparer.OrdinalIgnoreCase
|
||||
);
|
||||
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
var relationsToInsert = new List<ProductionItem2ODLModel>();
|
||||
|
||||
foreach (var odl in dbList)
|
||||
{
|
||||
var key = (odl.PhaseID ?? 0, odl.ResourceID ?? 0, odl.ProdPlantCod, odl.Index);
|
||||
|
||||
if (dictParts.TryGetValue(key, out List<string> tagList))
|
||||
{
|
||||
foreach (var tag in tagList)
|
||||
{
|
||||
// 3. Cerchiamo l'ID corrispondente al tag nel nostro lookup locale
|
||||
if (itemLookup.TryGetValue(tag, out int realItemId))
|
||||
{
|
||||
relationsToInsert.Add(new ProductionItem2ODLModel
|
||||
{
|
||||
ProdODLID = odl.ProdODLID,
|
||||
ProdItemID = realItemId,
|
||||
DtAssign = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (relationsToInsert.Any())
|
||||
{
|
||||
await dbCtx.DbSetProdItem2ODL.AddRangeAsync(relationsToInsert);
|
||||
totalCreated = relationsToInsert.Count;
|
||||
await dbCtx.SaveChangesAsync();
|
||||
}
|
||||
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return totalCreated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert sul DB di un elenco ODL con calcolo della relativa KEY a cui poter, successivamente, collegare i record child (items)
|
||||
/// </summary>
|
||||
/// <param name="listOdl2ins"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="Exception"></exception>
|
||||
public async Task<List<ProductionODLModel>> CreateAsync(List<ProductionODLModel> listOdl2ins)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// avvio transazione
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// verifico di avere dati
|
||||
if (listOdl2ins.Count == 0)
|
||||
{
|
||||
return listOdl2ins;
|
||||
}
|
||||
|
||||
int cYear = DateTime.Today.Year;
|
||||
// insert in blocco
|
||||
dbCtx.DbSetProdODL.AddRange(listOdl2ins);
|
||||
|
||||
// 3. Salvataggio massivo
|
||||
// EF Core 8 ottimizzerà gli insert in batch dove possibile
|
||||
await dbCtx.SaveChangesAsync();
|
||||
|
||||
// stored update Tags
|
||||
var pProdBatchID = new MySqlParameter("@pProdBatchID", listOdl2ins.FirstOrDefault()?.ProdBatchID ?? 0);
|
||||
var pPref = new MySqlParameter("@pPrefix", "ODL.");
|
||||
var pYear = new MySqlParameter("@pYear", cYear);
|
||||
await dbCtx.Database.ExecuteSqlRawAsync("CALL stp_ProdOdl_UpdateTag(@pProdBatchID, @pPrefix, @pYear)", pProdBatchID, pPref, pYear);
|
||||
|
||||
// 4. Conferma transazione
|
||||
await tx.CommitAsync();
|
||||
|
||||
// A questo punto, ogni oggetto in 'listOdl2ins' ha il ProdODLID aggiornato dal DB
|
||||
return listOdl2ins;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
// Logga l'errore secondo le tue necessità
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero record ProdOdl dato Tag/uID
|
||||
/// </summary>
|
||||
/// <param name="uID"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ProductionODLModel?> GetByUidAsync(string uID)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetProdODL
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.OdlTag == uID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco PODL non assegnati
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ProductionODLModel>> GetUnassignAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetProdODL
|
||||
.Where(x => !x.DateAssign.HasValue)
|
||||
.AsNoTracking()
|
||||
.Include(x => x.Item2OdlNav)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco PODL non assegnati con struttura DTO appiattita
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<OdlAssignDto>> GetUnassignOdlDtoAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetProdODL
|
||||
.Where(x => !x.DateAssign.HasValue)
|
||||
.AsNoTracking()
|
||||
.Select(odl => new OdlAssignDto
|
||||
{
|
||||
Envir = odl.ProdBatchNav.Envir,
|
||||
ProdODLID = odl.ProdODLID,
|
||||
Description = odl.Description,
|
||||
EstimTime = odl.EstimTime,
|
||||
Index = odl.Index,
|
||||
OdlTag = odl.OdlTag,
|
||||
PhaseID = odl.PhaseID,
|
||||
ProdBatchID = odl.ProdBatchID,
|
||||
ProdPlantCod = odl.ProdPlantCod,
|
||||
Qty = odl.Qty,
|
||||
ResourceID = odl.ResourceID,
|
||||
ItemList = odl.Item2OdlNav.Select(i => new ItemAssignDto
|
||||
{
|
||||
ProdItemID = i.ProdItemID,
|
||||
OrderID = i.ProductionItemNav.OrderRowNav.OrderNav.OrderID,
|
||||
OrderRowID = i.ProductionItemNav.OrderRowNav.OrderRowID,
|
||||
OrderTag = i.ProductionItemNav.OrderRowNav.OrderNav.OrderCode,
|
||||
OrderRowTag = i.ProductionItemNav.OrderRowNav.OrderRowCode,
|
||||
ProdItemTag = i.ProductionItemNav.ProdItemTag ?? "***"
|
||||
}).ToList()
|
||||
})
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update generico record
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpdateAsync(ProductionODLModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
var trackedEntity = await dbCtx.DbSetProdODL.FirstOrDefaultAsync(x => x.ProdODLID == entity.ProdODLID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetProdODL.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Production
|
||||
{
|
||||
public class ProductionPlantRepository : BaseRepository, IProductionPlantRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ProductionPlantRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<ProductionPlantModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetProdPlant
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public class CustomerRepository : BaseRepository, ICustomerRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public CustomerRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<CustomerModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetCustomer
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public class DealerRepository : BaseRepository, IDealerRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public DealerRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<DealerModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetDealer
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public interface ICustomerRepository
|
||||
{
|
||||
Task<List<CustomerModel>> GetAllAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public interface IDealerRepository
|
||||
{
|
||||
Task<List<DealerModel>> GetAllAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public interface IOfferRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(OfferModel entity);
|
||||
|
||||
Task<bool> CheckExpiredAsync();
|
||||
|
||||
Task<bool> CloneAsync(OfferModel rec2clone);
|
||||
|
||||
Task<bool> DeleteAsync(OfferModel entity);
|
||||
|
||||
Task<List<OfferModel>> GetAllAsync();
|
||||
|
||||
Task<List<ItemModel>> GetBomItemsAsync();
|
||||
|
||||
Task<OfferModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<List<OfferModel>> GetFiltAsync(DateTime inizio, DateTime fine);
|
||||
|
||||
Task<List<ItemGroupModel>> GetItemGroupsAsync();
|
||||
|
||||
Task<List<OfferRowModel>> GetRowsAsync(int recId);
|
||||
|
||||
Task<bool> SaveRowsAsync(List<OfferRowModel> rows);
|
||||
|
||||
Task<bool> UpdateAsync(OfferModel entity);
|
||||
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public interface IOfferRowRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(OfferRowModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(OfferRowModel entity);
|
||||
|
||||
Task<List<ItemModel>> GetBomItemsAsync();
|
||||
|
||||
Task<OfferRowModel?> GetByIdAsync(int offerRowId);
|
||||
|
||||
Task<List<OfferRowModel>> GetByParentAsync(int offerId);
|
||||
|
||||
Task<OfferRowModel?> GetByUidAsync(string offerRowUid);
|
||||
|
||||
Task<List<ItemGroupModel>> GetItemGroupsAsync();
|
||||
|
||||
Task<bool> SaveRowsAsync(List<OfferRowModel> rows);
|
||||
|
||||
Task<bool> UpdateAsync(OfferRowModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public interface IOrderRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(OrderModel entity);
|
||||
|
||||
Task<OrderModel?> CloneOfferAsync(OfferModel rec2clone);
|
||||
|
||||
Task<bool> DeleteAsync(OrderModel entity);
|
||||
|
||||
Task<List<OrderModel>> GetAllAsync();
|
||||
|
||||
Task<List<ItemModel>> GetBomItemsAsync();
|
||||
|
||||
Task<OrderModel?> GetByIdAsync(int recId);
|
||||
|
||||
Task<List<OrderModel>> GetFiltAsync(DateTime inizio, DateTime fine);
|
||||
|
||||
Task<List<ItemGroupModel>> GetItemGroupsAsync();
|
||||
|
||||
Task<List<OrderRowModel>> GetRowsAsync(int recId);
|
||||
|
||||
Task<bool> SaveRowsAsync(List<OrderRowModel> rows);
|
||||
|
||||
Task<bool> UpdateAsync(OrderModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public interface IOrderRowRepository : IBaseRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> AddAsync(OrderRowModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(OrderRowModel entity);
|
||||
|
||||
Task<List<ItemModel>> GetBomItemsAsync();
|
||||
|
||||
Task<OrderRowModel?> GetByIdAsync(int OrderRowId);
|
||||
|
||||
Task<List<OrderRowModel>> GetByParentAsync(int offerId);
|
||||
|
||||
Task<List<OrderRowModel>> GetByStateAsync(OrderStates reqState, DateTime dtStart, DateTime dtEnd);
|
||||
|
||||
Task<List<OrderRowModel>> GetByStateMinAsync(OrderStates reqState, DateTime dtStart, DateTime dtEnd);
|
||||
|
||||
Task<OrderRowModel?> GetByUidAsync(string OrderRowUid);
|
||||
|
||||
Task<List<ItemGroupModel>> GetItemGroupsAsync();
|
||||
|
||||
Task<bool> SaveProdEstAsync(string uID, string prodEstim);
|
||||
|
||||
Task<bool> SaveRowsAsync(List<OrderRowModel> rows);
|
||||
|
||||
Task<bool> UpdateAsync(OrderRowModel entity);
|
||||
|
||||
Task<int> ValidateAsync(List<OrderRowModel> list2chk);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public class OfferRepository : BaseRepository, IOfferRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public OfferRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(OfferModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetOffer.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> CheckExpiredAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
DateTime adesso = DateTime.Now;
|
||||
// recupero offerta...
|
||||
var listExpired = await dbCtx
|
||||
.DbSetOffer
|
||||
.Where(x => x.ValidUntil < adesso && x.OffertState == OfferStates.Open)
|
||||
.ToListAsync();
|
||||
|
||||
// se trovo le aggiorno come stato
|
||||
if (listExpired != null)
|
||||
{
|
||||
foreach (var item in listExpired)
|
||||
{
|
||||
item.OffertState = OfferStates.Expired;
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
// salvo TUTTI i cambiamenti...
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue il cloning completo di un Offerta e di TUTTE le relative righe...
|
||||
/// </summary>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CloneAsync(OfferModel rec2clone)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (parent + children clone)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
var currRec = await dbCtx.DbSetOffer
|
||||
.Include(x => x.OfferRowNav)
|
||||
.FirstOrDefaultAsync(x => x.OfferID == rec2clone.OfferID);
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
DateTime adesso = DateTime.Now;
|
||||
var lastRec = dbCtx
|
||||
.DbSetOffer
|
||||
.Where(x => x.RefYear == adesso.Year)
|
||||
.OrderByDescending(x => x.RefNum)
|
||||
.FirstOrDefault();
|
||||
int newRefNum = lastRec != null ? lastRec.RefNum + 1 : 1;
|
||||
|
||||
// 2. Creo il nuovo parent
|
||||
var newRec = new OfferModel()
|
||||
{
|
||||
ConsNote = rec2clone.ConsNote,
|
||||
CustomerID = rec2clone.CustomerID,
|
||||
DealerID = rec2clone.DealerID,
|
||||
Description = rec2clone.Description,
|
||||
DictPresel = rec2clone.DictPresel,
|
||||
Discount = rec2clone.Discount,
|
||||
DueDateProm = rec2clone.DueDateProm,
|
||||
DueDateReq = rec2clone.DueDateReq,
|
||||
Envir = rec2clone.Envir,
|
||||
Inserted = adesso,
|
||||
Modified = adesso,
|
||||
OffertState = OfferStates.Open,
|
||||
RefNum = newRefNum,
|
||||
RefRev = 1,
|
||||
RefYear = adesso.Year,
|
||||
ValidUntil = currRec.ValidUntil
|
||||
};
|
||||
|
||||
// 3. Clono i child
|
||||
// sistemo child...
|
||||
newRec.OfferRowNav = currRec.OfferRowNav
|
||||
.Select(c => new OfferRowModel()
|
||||
{
|
||||
AwaitBom = c.AwaitBom,
|
||||
AwaitPrice = c.AwaitPrice,
|
||||
BomCost = c.BomCost,
|
||||
BomOk = c.BomOk,
|
||||
BomPrice = c.BomPrice,
|
||||
Envir = c.Envir,
|
||||
FileName = c.FileName,
|
||||
FileResource = c.FileResource,
|
||||
FileSize = c.FileSize,
|
||||
Inserted = adesso,
|
||||
ItemBOM = c.ItemBOM,
|
||||
ItemJCD = c.ItemJCD,
|
||||
ItemOk = c.ItemOk,
|
||||
ItemSteps = c.ItemSteps,
|
||||
ItemTags = c.ItemTags,
|
||||
JobID = c.JobID,
|
||||
Modified = c.Modified,
|
||||
Note = c.Note,
|
||||
ProdItemQty = c.ProdItemQty,
|
||||
Qty = c.Qty,
|
||||
RowNum = c.RowNum,
|
||||
SellingItemID = c.SellingItemID,
|
||||
SerStruct = c.SerStruct,
|
||||
StepCost = c.StepCost,
|
||||
StepFlowTime = c.StepFlowTime,
|
||||
StepLeadTime = c.StepLeadTime,
|
||||
StepPrice = c.StepPrice,
|
||||
//OrderID = dbRec.OrderID,
|
||||
OfferRowUID = c.OfferRowDtx
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 4. Aggiungo il nuovo parent (EF aggiunge anche i child)
|
||||
dbCtx.DbSetOffer.Add(newRec);
|
||||
|
||||
// 5. Salvo tutto in transazione
|
||||
await dbCtx.SaveChangesAsync();
|
||||
await tx.CommitAsync();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(OfferModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetOffer.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<OfferModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOffer
|
||||
.Include(c => c.CustomerNav)
|
||||
.Include(d => d.DealerNav)
|
||||
.Include(o => o.OfferRowNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetBomItemsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => x.ItemType == ItemClassType.Bom || x.ItemType == ItemClassType.BomAlt)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<OfferModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOffer.FirstOrDefaultAsync(x => x.OfferID == recId);
|
||||
}
|
||||
|
||||
public async Task<List<OfferModel>> GetFiltAsync(DateTime inizio, DateTime fine)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOffer
|
||||
.Where(x => x.Inserted >= inizio && x.Inserted <= fine)
|
||||
.Include(c => c.CustomerNav)
|
||||
.Include(d => d.DealerNav)
|
||||
.Include(o => o.OfferRowNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemGroupModel>> GetItemGroupsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItemGroup.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<OfferRowModel>> GetRowsAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOfferRow
|
||||
.Where(x => x.OfferID == recId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveRowsAsync(List<OfferRowModel> rows)
|
||||
{
|
||||
// Add validation for null or empty list
|
||||
if (rows == null || rows.Count == 0) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (batch update multiple rows)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
foreach (var row in rows)
|
||||
dbCtx.Entry(row).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(OfferModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetOffer.FirstOrDefaultAsync(x => x.OfferID == entity.OfferID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// verifico eventuale riapertura SE fosse expired ma la data è valida...
|
||||
if (trackedEntity.OffertState == OfferStates.Expired && entity.ValidUntil > DateTime.Today)
|
||||
{
|
||||
entity.OffertState = OfferStates.Open;
|
||||
}
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetOffer.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public class OfferRowRepository : BaseRepository, IOfferRowRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public OfferRowRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(OfferRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync(); await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// SE ci fossero righe di indice pari o superiore le deve spostare...
|
||||
// 2. Recupero i record successivi da shiftare
|
||||
var list2Move = await dbCtx.DbSetOfferRow
|
||||
.Where(x => x.OfferID == entity.OfferID && x.RowNum >= entity.RowNum)
|
||||
.ToListAsync();
|
||||
|
||||
// aggiungo record
|
||||
await dbCtx.DbSetOfferRow.AddAsync(entity);
|
||||
foreach (var item in list2Move)
|
||||
{
|
||||
item.RowNum++;
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(OfferRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (multi-row update + delete)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// 1. Recupero il record da eliminare
|
||||
var dbResult = await dbCtx.DbSetOfferRow
|
||||
.FirstOrDefaultAsync(x => x.OfferRowID == entity.OfferRowID);
|
||||
|
||||
if (dbResult == null)
|
||||
return false;
|
||||
|
||||
// 2. Recupero i record successivi da shiftare
|
||||
var list2Move = await dbCtx.DbSetOfferRow
|
||||
.Where(x => x.OfferID == entity.OfferID && x.RowNum > dbResult.RowNum)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in list2Move)
|
||||
{
|
||||
item.RowNum--;
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
// 3. Rimuovo il record
|
||||
dbCtx.DbSetOfferRow.Remove(dbResult);
|
||||
|
||||
// 4. Salvo tutto
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetBomItemsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => x.ItemType == ItemClassType.Bom || x.ItemType == ItemClassType.BomAlt)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<OfferRowModel?> GetByIdAsync(int offerRowId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOfferRow
|
||||
.Include(r => r.SellingItemNav)
|
||||
.FirstOrDefaultAsync(x => x.OfferRowID == offerRowId);
|
||||
}
|
||||
|
||||
public async Task<List<OfferRowModel>> GetByParentAsync(int offerId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOfferRow
|
||||
.Where(x => x.OfferID == offerId)
|
||||
.Include(r => r.SellingItemNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<OfferRowModel?> GetByUidAsync(string offerRowUid)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOfferRow
|
||||
.Include(r => r.SellingItemNav)
|
||||
.FirstOrDefaultAsync(x => x.OfferRowUID == offerRowUid);
|
||||
}
|
||||
|
||||
public async Task<List<ItemGroupModel>> GetItemGroupsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItemGroup.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveRowsAsync(List<OfferRowModel> rows)
|
||||
{
|
||||
// Add validation for null or empty list
|
||||
if (rows == null || rows.Count == 0) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (batch update multiple rows)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
foreach (var row in rows)
|
||||
dbCtx.Entry(row).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(OfferRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetOfferRow.FirstOrDefaultAsync(x => x.OfferRowID == entity.OfferRowID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetOfferRow.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public class OrderRepository : BaseRepository, IOrderRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public OrderRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(OrderModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetOrder.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue il cloning completo di un Offerta e di TUTTE le relative righe...
|
||||
/// </summary>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<OrderModel?> CloneOfferAsync(OfferModel rec2clone)
|
||||
{
|
||||
OrderModel? newRec = null;
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// avvio transazione
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
var currRec = await dbCtx.DbSetOffer
|
||||
.Include(x => x.OfferRowNav)
|
||||
.FirstOrDefaultAsync(x => x.OfferID == rec2clone.OfferID);
|
||||
|
||||
if (currRec == null)
|
||||
return null;
|
||||
|
||||
DateTime adesso = DateTime.Now;
|
||||
var lastRec = dbCtx
|
||||
.DbSetOrder
|
||||
.Where(x => x.RefYear == adesso.Year)
|
||||
.OrderByDescending(x => x.RefNum)
|
||||
.FirstOrDefault();
|
||||
int newRefNum = lastRec != null ? lastRec.RefNum + 1 : 1;
|
||||
|
||||
// 2. Creo il nuovo parent
|
||||
newRec = new OrderModel()
|
||||
{
|
||||
ConsNote = rec2clone.ConsNote,
|
||||
CustomerID = rec2clone.CustomerID,
|
||||
DealerID = rec2clone.DealerID,
|
||||
Description = rec2clone.Description,
|
||||
DictPresel = rec2clone.DictPresel,
|
||||
Discount = rec2clone.Discount,
|
||||
DueDateProm = rec2clone.DueDateProm,
|
||||
DueDateReq = rec2clone.DueDateReq,
|
||||
Envir = rec2clone.Envir,
|
||||
Inserted = adesso,
|
||||
Modified = adesso,
|
||||
OfferID = rec2clone.OfferID,
|
||||
OrderState = OrderStates.Created,
|
||||
RefNum = newRefNum,
|
||||
RefRev = 1,
|
||||
RefYear = adesso.Year,
|
||||
ValidUntil = currRec.ValidUntil
|
||||
};
|
||||
|
||||
// 3. Clono i child
|
||||
// sistemo child...
|
||||
newRec.OrderRowNav = currRec.OfferRowNav
|
||||
.Select(c => new OrderRowModel()
|
||||
{
|
||||
AwaitBom = c.AwaitBom,
|
||||
AwaitPrice = c.AwaitPrice,
|
||||
BomCost = c.BomCost,
|
||||
BomOk = c.BomOk,
|
||||
BomPrice = c.BomPrice,
|
||||
Envir = c.Envir,
|
||||
FileName = c.FileName,
|
||||
FileResource = c.FileResource,
|
||||
FileSize = c.FileSize,
|
||||
Inserted = adesso,
|
||||
ItemBOM = c.ItemBOM,
|
||||
ItemJCD = c.ItemJCD,
|
||||
ItemOk = c.ItemOk,
|
||||
ItemSteps = c.ItemSteps,
|
||||
ItemTags = c.ItemTags,
|
||||
JobID = c.JobID,
|
||||
Modified = adesso,
|
||||
Note = c.Note,
|
||||
ProdItemQty = c.ProdItemQty,
|
||||
Qty = c.Qty,
|
||||
RowNum = c.RowNum,
|
||||
SellingItemID = c.SellingItemID,
|
||||
SerStruct = c.SerStruct,
|
||||
StepCost = c.StepCost,
|
||||
StepFlowTime = c.StepFlowTime,
|
||||
StepLeadTime = c.StepLeadTime,
|
||||
StepPrice = c.StepPrice
|
||||
})
|
||||
.ToList();
|
||||
|
||||
// 4. Aggiungo il nuovo parent (EF aggiunge anche i child)
|
||||
dbCtx.DbSetOrder.Add(newRec);
|
||||
|
||||
// 5. Salvo tutto
|
||||
var numSave = await dbCtx.SaveChangesAsync();
|
||||
|
||||
// se ok sistemo UID...
|
||||
if (numSave > 0 && newRec != null)
|
||||
{
|
||||
// sistemo UID...
|
||||
foreach (var item in newRec.OrderRowNav)
|
||||
{
|
||||
item.OrderRowUID = item.OrderRowCode;
|
||||
// alternativa da valutare..
|
||||
if (false)
|
||||
{
|
||||
// genero tanti record collegati alla riga d'ordine...
|
||||
for (int i = 0; i < item.ProdItemQtyTot; i++)
|
||||
{
|
||||
var child = new ProductionItemModel
|
||||
{
|
||||
OrderRowID = item.OrderRowID,
|
||||
//OrderRowNav = item,
|
||||
ItemCode = i + 1,
|
||||
ExtItemCode = $"{item.OrderRowCode}-{i + 1:000}",
|
||||
ProdBatchID = null
|
||||
};
|
||||
// aggiungo record
|
||||
item.ProdItemNav.Add(child);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item.ProdItemNav = Enumerable.Range(1, (int)item.ProdItemQtyTot)
|
||||
.Select(i => new ProductionItemModel
|
||||
{
|
||||
//OrderRowID = item.OrderRowID,
|
||||
OrderRowNav = item,
|
||||
ItemCode = i,
|
||||
ExtItemCode = $"{item.OrderRowCode}-{i:000}",
|
||||
ProdBatchID = null,
|
||||
ProdItemTag = null //nullo e POI verrà sistemato
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
// salvo ulteriori variazioni
|
||||
await dbCtx.SaveChangesAsync();
|
||||
// tutti gli ordini e anno corrente...
|
||||
await dbCtx.Database.ExecuteSqlRawAsync("CALL stp_ProdItem_UpdateProdItemTag(0,0);");
|
||||
|
||||
// committo in un unica transazione (da provare!!!)
|
||||
await tx.CommitAsync();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
return newRec;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(OrderModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetOrder.Remove(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<List<OrderModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrder
|
||||
.Include(c => c.CustomerNav)
|
||||
.Include(d => d.DealerNav)
|
||||
.Include(o => o.OrderRowNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetBomItemsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => x.ItemType == ItemClassType.Bom || x.ItemType == ItemClassType.BomAlt)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<OrderModel?> GetByIdAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrder.FirstOrDefaultAsync(x => x.OrderID == recId);
|
||||
}
|
||||
|
||||
public async Task<List<OrderModel>> GetFiltAsync(DateTime inizio, DateTime fine)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrder
|
||||
.Where(x => x.Inserted >= inizio && x.Inserted <= fine)
|
||||
.Include(c => c.CustomerNav)
|
||||
.Include(d => d.DealerNav)
|
||||
.Include(o => o.OrderRowNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<ItemGroupModel>> GetItemGroupsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItemGroup.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<OrderRowModel>> GetRowsAsync(int recId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrderRow
|
||||
.Where(x => x.OrderID == recId)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveRowsAsync(List<OrderRowModel> rows)
|
||||
{
|
||||
// Add validation for null or empty list
|
||||
if (rows == null || rows.Count == 0) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (batch update multiple rows)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
foreach (var row in rows)
|
||||
dbCtx.Entry(row).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(OrderModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetOrder.FirstOrDefaultAsync(x => x.OrderID == entity.OrderID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetOrder.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
using EgwCoreLib.Lux.Core.Generic;
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Items;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Production;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Sales;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Newtonsoft.Json;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Sales
|
||||
{
|
||||
public class OrderRowRepository : BaseRepository, IOrderRowRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public OrderRowRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<bool> AddAsync(OrderRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetOrderRow.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(OrderRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (multi-row update + delete)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// 1. Recupero il record da eliminare
|
||||
var dbResult = await dbCtx.DbSetOrderRow
|
||||
.FirstOrDefaultAsync(x => x.OrderRowID == entity.OrderRowID);
|
||||
|
||||
if (dbResult == null)
|
||||
return false;
|
||||
|
||||
// 2. Recupero i record successivi da shiftare
|
||||
var list2Move = await dbCtx.DbSetOrderRow
|
||||
.Where(x => x.OrderID == entity.OrderID && x.RowNum > dbResult.RowNum)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in list2Move)
|
||||
{
|
||||
item.RowNum--;
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
// 3. Rimuovo il record
|
||||
dbCtx.DbSetOrderRow.Remove(dbResult);
|
||||
|
||||
// 4. Salvo tutto
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<List<ItemModel>> GetBomItemsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItem
|
||||
.Where(x => x.ItemType == ItemClassType.Bom || x.ItemType == ItemClassType.BomAlt)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<OrderRowModel?> GetByIdAsync(int OrderRowId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrderRow
|
||||
.Include(r => r.SellingItemNav)
|
||||
.FirstOrDefaultAsync(x => x.OrderRowID == OrderRowId);
|
||||
}
|
||||
|
||||
public async Task<List<OrderRowModel>> GetByParentAsync(int orderId)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrderRow
|
||||
.Where(x => x.OrderID == orderId)
|
||||
.Include(r => r.SellingItemNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<OrderRowModel>> GetByStateAsync(OrderStates reqState, DateTime dtStart, DateTime dtEnd)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrderRow
|
||||
.Where(x => x.OrderRowState == reqState && x.Inserted >= dtStart && x.Inserted <= dtEnd)
|
||||
.Include(r => r.SellingItemNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<List<OrderRowModel>> GetByStateMinAsync(OrderStates reqState, DateTime dtStart, DateTime dtEnd)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrderRow
|
||||
.Where(x => x.OrderRowState >= reqState && x.Inserted >= dtStart && x.Inserted <= dtEnd)
|
||||
.Include(r => r.SellingItemNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<OrderRowModel?> GetByUidAsync(string OrderRowUid)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetOrderRow
|
||||
.Include(r => r.SellingItemNav)
|
||||
.FirstOrDefaultAsync(x => x.OrderRowUID == OrderRowUid);
|
||||
}
|
||||
|
||||
public async Task<List<ItemGroupModel>> GetItemGroupsAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetItemGroup.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<bool> SaveRowsAsync(List<OrderRowModel> rows)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (batch update multiple rows)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
foreach (var row in rows)
|
||||
dbCtx.Entry(row).State = EntityState.Modified;
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(OrderRowModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = await dbCtx.DbSetOrderRow.FirstOrDefaultAsync(x => x.OrderRowID == entity.OrderRowID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbCtx.DbSetOrderRow.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> SaveProdEstAsync(string uID, string prodEstim)
|
||||
{
|
||||
// Add validation for null or empty list
|
||||
if (string.IsNullOrWhiteSpace(uID) || string.IsNullOrWhiteSpace(prodEstim)) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// Wrap in transaction for atomicity (batch update multiple rows)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// recupero offerta...
|
||||
var currRec = dbCtx
|
||||
.DbSetOrderRow
|
||||
.Where(x => x.OrderRowUID == uID)
|
||||
.FirstOrDefault();
|
||||
|
||||
// se trovo aggiorno
|
||||
if (currRec != null)
|
||||
{
|
||||
// genero WLD x controllo
|
||||
var currWLD = new WorkLoadDetailDTO(currRec.OrderRowUID, currRec.ProdEstimate);
|
||||
|
||||
// faccio update in cascata dei record collegati x macchine e items
|
||||
var listMachDb = dbCtx
|
||||
.DbSetProdPlant
|
||||
.Select(x => x.ProdPlantCod)
|
||||
.ToList();
|
||||
List<string> listMaccCurr = currWLD.MachineCalcResults.Select(x => x.Name).OrderBy(x => x).ToList() ?? new List<string>();
|
||||
if (listMaccCurr != null && listMaccCurr.Any())
|
||||
{
|
||||
var listDiff = listMaccCurr.Except(listMachDb).ToList();
|
||||
if (listDiff.Any())
|
||||
{
|
||||
foreach (var macch in listDiff)
|
||||
{
|
||||
dbCtx
|
||||
.DbSetProdPlant
|
||||
.Add(new ProductionPlantModel() { ProdPlantCod = macch, ProdPlantDescript = macch });
|
||||
}
|
||||
}
|
||||
}
|
||||
// resetta assegnazioni prodgroup agli items...
|
||||
List<ProductionItemModel> listItem2upd = await dbCtx
|
||||
.DbSetProdItem
|
||||
.Where(x => x.OrderRowID == currRec.OrderRowID && x.ProdGroupID != null)
|
||||
.ToListAsync();
|
||||
if (listItem2upd != null && listItem2upd.Count > 0)
|
||||
{
|
||||
// li aggiorna tutti resettando ProdGroupID
|
||||
listItem2upd.ForEach(x => x.ProdGroupID = null);
|
||||
}
|
||||
|
||||
// elimina eventuali oggetti ProductionGroup precedenti
|
||||
List<ProductionGroupModel> listProdGroup2Rem = await dbCtx
|
||||
.DbSetProdGroup
|
||||
.Where(x => x.OrderRowID == currRec.OrderRowID)
|
||||
.ToListAsync();
|
||||
// rimuovo...
|
||||
if (listProdGroup2Rem != null && listProdGroup2Rem.Count > 0)
|
||||
{
|
||||
dbCtx.DbSetProdGroup.RemoveRange(listProdGroup2Rem);
|
||||
}
|
||||
|
||||
/*----------------------------------
|
||||
* Generazione ProdGroup
|
||||
* FixMe ToDo !!!
|
||||
*
|
||||
* rifare considerando le REALI combinazioni scaturite x questo specifico caso e
|
||||
* - ENUMERARE le combinazioni
|
||||
* - ogni combinazione sarà un caso specifico tra 0...N dove N è il totale delle macchine gestite
|
||||
* - i successivi calcoli di balance/stima saranno fatti x questo SPECIFICO ID GROUP così da fare prima... a sto punto GroupIP potrebbe essere un int 0...n oppure l'id del record... forse meglio il counter 0..n
|
||||
*
|
||||
* */
|
||||
int grpIdx = 1;
|
||||
// preparo x add nuovi ProductionGroup da analisi ritorno stime
|
||||
List<ProductionGroupModel> listProdGroup2Add = new List<ProductionGroupModel>();
|
||||
// 1: non lavorabili...
|
||||
if (currWLD.ListUnWorkable.Count > 0)
|
||||
{
|
||||
// calcolo il dizionario degli elementi...
|
||||
Dictionary<string, ProdMachineDetailDto> newWorkGroupList = new();
|
||||
ProdMachineDetailDto detProd = new ProdMachineDetailDto()
|
||||
{
|
||||
TagList = currWLD.ListUnWorkable
|
||||
};
|
||||
newWorkGroupList.Add("", detProd);
|
||||
string rawWGL = JsonConvert.SerializeObject(newWorkGroupList);
|
||||
ProductionGroupModel newRec = new ProductionGroupModel()
|
||||
{
|
||||
OrderRowID = currRec.OrderRowID,
|
||||
GrpIdx = grpIdx++,
|
||||
WorkGroupListRaw = rawWGL
|
||||
};
|
||||
listProdGroup2Add.Add(newRec);
|
||||
}
|
||||
|
||||
// dizionario x macchina delle parts LAVORABILI su impianto..
|
||||
var machineTags = currWLD.MachineCalcResults
|
||||
.ToDictionary(
|
||||
m => m.Name,
|
||||
m => m.PartList
|
||||
.Where(p => p.CalcResult == EgwCoreLib.Lux.Core.Enums.PartVerificationResult.MACHINABLE)
|
||||
.ToList()
|
||||
);
|
||||
|
||||
// ciclo x tutte le combinazioni di gruppi lavorabilità...
|
||||
foreach (var item in currWLD.LoadDetail)
|
||||
{
|
||||
// calcolo il dizionario degli elementi...
|
||||
Dictionary<string, ProdMachineDetailDto> newWorkGroupList = new();
|
||||
foreach (var machineName in item.Machines)
|
||||
{
|
||||
decimal effectiveTime = 0;
|
||||
// Recuperiamo i dati della macchina dal dizionario
|
||||
if (machineTags.TryGetValue(machineName, out var machineParts))
|
||||
{
|
||||
// Creiamo un set dei tag del gruppo per una ricerca veloce O(1)
|
||||
var groupTagsSet = item.Tags.ToHashSet();
|
||||
|
||||
// Sommiamo il tempo solo per i pezzi che appartengono a questo gruppo
|
||||
effectiveTime = machineParts
|
||||
.Where(p => groupTagsSet.Contains(p.Tag))
|
||||
.Sum(p => p.Time);
|
||||
}
|
||||
|
||||
ProdMachineDetailDto detProd = new ProdMachineDetailDto()
|
||||
{
|
||||
TagList = item.Tags,
|
||||
Time = effectiveTime // Tempo reale specifico per questa macchina/gruppo
|
||||
};
|
||||
newWorkGroupList.Add(machineName, detProd);
|
||||
}
|
||||
string rawWGL = JsonConvert.SerializeObject(newWorkGroupList);
|
||||
ProductionGroupModel newRec = new ProductionGroupModel()
|
||||
{
|
||||
OrderRowID = currRec.OrderRowID,
|
||||
GrpIdx = grpIdx++,
|
||||
WorkGroupListRaw = rawWGL
|
||||
};
|
||||
listProdGroup2Add.Add(newRec);
|
||||
}
|
||||
// aggiungo i record...
|
||||
dbCtx.DbSetProdGroup.AddRange(listProdGroup2Add);
|
||||
|
||||
// aggiorno info Estimation, tempi e stato
|
||||
currRec.ProdEstimate = prodEstim;
|
||||
if (!string.IsNullOrEmpty(prodEstim))
|
||||
{
|
||||
currRec.OrderRowState = OrderStates.Estimated;
|
||||
}
|
||||
var totEstim = listProdGroup2Add.Sum(x => x.TotalEstimTime);
|
||||
currRec.ProdEstimTime = totEstim;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
// salvo TUTTI i cambiamenti...
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<int> ValidateAsync(List<OrderRowModel> list2chk)
|
||||
{
|
||||
int numDone = 0;
|
||||
|
||||
// Add validation for null or empty list
|
||||
if (list2chk.Count == 0)
|
||||
return numDone;
|
||||
|
||||
// context
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Wrap in transaction for atomicity (batch update multiple rows)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// verifica preliminare: serve SSE stato e estimate non corrispondono...
|
||||
var list2fix = list2chk
|
||||
.Where(x => x.OrderRowState == OrderStates.Created && !string.IsNullOrEmpty(x.ProdEstimate))
|
||||
.ToList();
|
||||
|
||||
if (list2fix.Any())
|
||||
{
|
||||
// per ogni record processo intera validazione
|
||||
foreach (var item in list2fix)
|
||||
{
|
||||
bool fatto = await SaveProdEstAsync(item.OrderRowUID, item.ProdEstimate);
|
||||
numDone += fatto ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// salvo TUTTI i cambiamenti...
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return numDone;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Stats;
|
||||
using EgwCoreLib.Utils;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Stats
|
||||
{
|
||||
public interface IStatsAggrRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<List<StatsAggregatedModel>> GetFiltAsync(DateTime dtStart, DateTime dtEnd);
|
||||
|
||||
Task<DtUtils.Periodo> GetRangeAsync();
|
||||
|
||||
Task<int> UpsertManyAsync(List<StatsAggregatedModel> listRecords, bool removeOld);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Stats;
|
||||
using EgwCoreLib.Utils;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Stats
|
||||
{
|
||||
public interface IStatsDetailRepository
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<List<StatsDetailModel>> GetFiltAsync(DateTime dtStart, DateTime dtEnd, string sEnvir = "", string sType = "");
|
||||
|
||||
Task<DtUtils.Periodo> GetRangeAsync(string sEnvir, string sType);
|
||||
|
||||
Task<int> UpsertManyAsync(List<StatsDetailModel> listRecords, bool removeOld);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Stats;
|
||||
using EgwCoreLib.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Stats
|
||||
{
|
||||
public class StatsAggrRepository : BaseRepository, IStatsAggrRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public StatsAggrRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Elenco da DB delel stats aggregate dato periodo inizio/fine
|
||||
/// </summary>
|
||||
/// <param name="dtStart"></param>
|
||||
/// <param name="dtEnd"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<StatsAggregatedModel>> GetFiltAsync(DateTime dtStart, DateTime dtEnd)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx
|
||||
.DbSetStatsAggr
|
||||
.Where(x => x.Hour >= dtStart && x.Hour <= dtEnd)
|
||||
.AsNoTracking()
|
||||
.OrderBy(x => x.Hour)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Range periodo per chiamate aggregate
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<DtUtils.Periodo> GetRangeAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
DtUtils.Periodo answ = new DtUtils.Periodo(DtUtils.PeriodSet.Today);
|
||||
var query = dbCtx.DbSetStatsAggr.AsQueryable();
|
||||
var minHour = await query.MinAsync(x => x.Hour);
|
||||
var maxHour = await query.MaxAsync(x => x.Hour);
|
||||
answ.Inizio = minHour;
|
||||
answ.Fine = maxHour;
|
||||
// ritorno!
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue insert statistiche aggregate sul DB
|
||||
/// </summary>
|
||||
/// <param name="listRecords">Elenco dei record da inserire</param>
|
||||
/// <param name="removeOld">Se true preventivamente elimina record nel periodo richiesto</param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> UpsertManyAsync(List<StatsAggregatedModel> listRecords, bool removeOld)
|
||||
{
|
||||
int answ = 0;
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// in primis se richiesto calcolo range periodo e svuoto...
|
||||
if (removeOld)
|
||||
{
|
||||
var firstRec = listRecords.OrderBy(x => x.Hour).FirstOrDefault();
|
||||
var lastRec = listRecords.OrderByDescending(x => x.Hour).FirstOrDefault();
|
||||
|
||||
if (firstRec != null && lastRec != null)
|
||||
{
|
||||
DateTime startDate = firstRec.Hour;
|
||||
DateTime endDate = lastRec.Hour;
|
||||
// uso direttamente ExecuteDelete
|
||||
await dbCtx
|
||||
.DbSetStatsAggr
|
||||
.Where(x => x.Hour >= startDate && x.Hour <= endDate)
|
||||
.ExecuteDeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
// ora preparo inserimento massivo
|
||||
await dbCtx
|
||||
.DbSetStatsAggr
|
||||
.AddRangeAsync(listRecords);
|
||||
|
||||
// salvo!
|
||||
answ = await dbCtx.SaveChangesAsync();
|
||||
|
||||
// commit transazione
|
||||
await tx.CommitAsync();
|
||||
|
||||
// libero memoria del changeTracker
|
||||
dbCtx.ChangeTracker.Clear();
|
||||
return answ;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Stats;
|
||||
using EgwCoreLib.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Stats
|
||||
{
|
||||
public class StatsDetailRepository : BaseRepository, IStatsDetailRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public StatsDetailRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
/// <summary>
|
||||
/// Recupera dati stats di dettaglio dato filtro envir/tipo (opzionali) e periodo
|
||||
/// </summary>
|
||||
/// <param name="dtStart"></param>
|
||||
/// <param name="dtEnd"></param>
|
||||
/// <param name="sEnvir"></param>
|
||||
/// <param name="sType"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<StatsDetailModel>> GetFiltAsync(DateTime dtStart, DateTime dtEnd, string sEnvir = "", string sType = "")
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
List<StatsDetailModel> answ = new List<StatsDetailModel>();
|
||||
|
||||
// recupero ed ordino per data-ora
|
||||
var query = dbCtx.DbSetStatsDet
|
||||
.Where(x => x.Hour >= dtStart && x.Hour <= dtEnd);
|
||||
|
||||
if (!string.IsNullOrEmpty(sEnvir))
|
||||
query = query.Where(x => x.Environment == sEnvir);
|
||||
|
||||
if (!string.IsNullOrEmpty(sType))
|
||||
query = query.Where(x => x.Type == sType);
|
||||
|
||||
answ = await query
|
||||
.AsNoTracking()
|
||||
.OrderBy(x => x.Hour)
|
||||
.ThenBy(x => x.Environment)
|
||||
.ThenBy(x => x.Type)
|
||||
.ToListAsync();
|
||||
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Range periodo x chiamate detail eventualmente filtrate
|
||||
/// </summary>
|
||||
/// <param name="sEnvir"></param>
|
||||
/// <param name="sType"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<DtUtils.Periodo> GetRangeAsync(string sEnvir, string sType)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
DtUtils.Periodo answ = new DtUtils.Periodo(DtUtils.PeriodSet.Today);
|
||||
|
||||
var query = dbCtx.DbSetStatsDet.AsQueryable();
|
||||
|
||||
if (!string.IsNullOrEmpty(sEnvir))
|
||||
query = query.Where(x => x.Environment == sEnvir);
|
||||
|
||||
if (!string.IsNullOrEmpty(sType))
|
||||
query = query.Where(x => x.Type == sType);
|
||||
|
||||
var minHour = await query.MinAsync(x => x.Hour);
|
||||
var maxHour = await query.MaxAsync(x => x.Hour);
|
||||
answ.Inizio = minHour;
|
||||
answ.Fine = maxHour;
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue insert statistiche di dettaglio sul DB
|
||||
/// </summary>
|
||||
/// <param name="listRecords">Elenco dei record da inserire</param>
|
||||
/// <param name="removeOld">Se true preventivamente elimina record nel periodo richiesto</param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> UpsertManyAsync(List<StatsDetailModel> listRecords, bool removeOld)
|
||||
{
|
||||
int answ = 0;
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// in primis se richiesto calcolo range periodo e svuoto...
|
||||
if (removeOld)
|
||||
{
|
||||
var firstRec = listRecords.OrderBy(x => x.Hour).FirstOrDefault();
|
||||
var lastRec = listRecords.OrderByDescending(x => x.Hour).FirstOrDefault();
|
||||
|
||||
if (firstRec != null && lastRec != null)
|
||||
{
|
||||
DateTime startDate = firstRec.Hour;
|
||||
DateTime endDate = lastRec.Hour;
|
||||
// uso direttamente ExecuteDelete
|
||||
await dbCtx
|
||||
.DbSetStatsDet
|
||||
.Where(x => x.Hour >= startDate && x.Hour <= endDate)
|
||||
.ExecuteDeleteAsync();
|
||||
}
|
||||
}
|
||||
|
||||
// ora preparo inserimento massivo
|
||||
await dbCtx
|
||||
.DbSetStatsDet
|
||||
.AddRangeAsync(listRecords);
|
||||
|
||||
// salvo!
|
||||
answ = await dbCtx.SaveChangesAsync();
|
||||
// commit transazione
|
||||
await tx.CommitAsync();
|
||||
|
||||
// libero memoria del changeTracker
|
||||
dbCtx.ChangeTracker.Clear();
|
||||
return answ;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Internal Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MySqlConnector;
|
||||
using System.Data;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public class CounterRepository : BaseRepository, ICounterRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public CounterRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<CounterModel>> GetAllAsync(int? yearRef = null)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetCounters
|
||||
.AsNoTracking()
|
||||
.Where(x => yearRef == null || x.RefYear == yearRef)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
public async Task<int> GetNextAsync(int yearRef, string countName)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
int newCount = 0;
|
||||
var outParam = new MySqlParameter("@pValue", MySqlDbType.Int32)
|
||||
{
|
||||
Direction = ParameterDirection.Output
|
||||
};
|
||||
|
||||
await dbCtx.Database.ExecuteSqlRawAsync(
|
||||
"CALL GetNextCounter(@pYear, @pName, @pValue);",
|
||||
new MySqlParameter("@pYear", yearRef),
|
||||
new MySqlParameter("@pName", countName),
|
||||
outParam
|
||||
);
|
||||
if (outParam != null)
|
||||
{
|
||||
int.TryParse($"{outParam.Value}", out newCount);
|
||||
}
|
||||
return newCount;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -7,48 +7,72 @@ namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public GenClassRepository(DataLayerContext db) : base(db)
|
||||
public GenClassRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
public async Task<bool> AddAsync(GenClassModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetGenClass.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(GenClassModel entity)
|
||||
{
|
||||
// Add validation for null entity
|
||||
if (entity == null) return false;
|
||||
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
dbCtx.DbSetGenClass.Remove(entity);
|
||||
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
public void Add(GenClassModel entity) => _dbCtx.DbSetGenClass.Add(entity);
|
||||
|
||||
public async Task<int> CountChildrenAsync(string classCod)
|
||||
{
|
||||
return await _dbCtx.DbSetGenVal.CountAsync(x => x.ClassCod == classCod);
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetGenVal.CountAsync(x => x.ClassCod == classCod);
|
||||
}
|
||||
|
||||
public void Delete(GenClassModel entity) => _dbCtx.DbSetGenClass.Remove(entity);
|
||||
public async Task<List<GenClassModel>> GetAllWithNavAsync()
|
||||
public async Task<List<GenClassModel>> GetAllAsync()
|
||||
{
|
||||
// EF Core 8 è già molto veloce, lasciamo che l'eccezione salga
|
||||
return await _dbCtx.DbSetGenClass
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetGenClass
|
||||
.Include(o => o.GenValNav)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<GenClassModel?> GetByCodeAsync(string code) =>
|
||||
await _dbCtx.DbSetGenClass.FirstOrDefaultAsync(x => x.ClassCod == code);
|
||||
|
||||
public void Update(GenClassModel entity)
|
||||
public async Task<GenClassModel?> GetByCodeAsync(string code)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetGenClass.FirstOrDefaultAsync(x => x.ClassCod == code);
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAsync(GenClassModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = _dbCtx.DbSetGenClass.Local.FirstOrDefault(x => x.ClassCod == entity.ClassCod);
|
||||
var trackedEntity = await dbCtx.DbSetGenClass.FirstOrDefaultAsync(x => x.ClassCod == entity.ClassCod);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
_dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbCtx.DbSetGenClass.Update(entity);
|
||||
dbCtx.DbSetGenClass.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
@@ -3,11 +3,11 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
internal class GenValRepository : BaseRepository, IGenValRepository
|
||||
public class GenValRepository : BaseRepository, IGenValRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public GenValRepository(DataLayerContext db) : base(db)
|
||||
public GenValRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -15,42 +15,70 @@ namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Add(GenValueModel entity) => _dbCtx.DbSetGenVal.Add(entity);
|
||||
public async Task<bool> AddAsync(GenValueModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
await dbCtx.DbSetGenVal.AddAsync(entity);
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(GenValueModel rec2del)
|
||||
{
|
||||
// 1. Recupero il record da eliminare
|
||||
var dbResult = await _dbCtx.DbSetGenVal
|
||||
.FirstOrDefaultAsync(x => x.GenValID == rec2del.GenValID);
|
||||
// Add validation for null entity
|
||||
if (rec2del == null) return false;
|
||||
|
||||
if (dbResult == null)
|
||||
return false;
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// 2. Recupero i record successivi da shiftare
|
||||
var list2Move = await _dbCtx.DbSetGenVal
|
||||
.Where(x => x.ClassCod == rec2del.ClassCod && x.Index > dbResult.Index)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in list2Move)
|
||||
// Wrap in transaction for atomicity (multi-row update + delete)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
item.Index--;
|
||||
_dbCtx.Entry(item).State = EntityState.Modified;
|
||||
// 1. Recupero il record da eliminare
|
||||
var dbResult = await dbCtx.DbSetGenVal
|
||||
.FirstOrDefaultAsync(x => x.GenValID == rec2del.GenValID);
|
||||
|
||||
if (dbResult == null)
|
||||
return false;
|
||||
|
||||
// 2. Recupero i record successivi da shiftare
|
||||
var list2Move = await dbCtx.DbSetGenVal
|
||||
.Where(x => x.ClassCod == rec2del.ClassCod && x.Index > dbResult.Index)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in list2Move)
|
||||
{
|
||||
item.Index--;
|
||||
dbCtx.Entry(item).State = EntityState.Modified;
|
||||
}
|
||||
|
||||
// 3. Rimuovo il record
|
||||
dbCtx.DbSetGenVal.Remove(dbResult);
|
||||
|
||||
// 4. Salvo tutto
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
|
||||
// 3. Rimuovo il record
|
||||
_dbCtx.DbSetGenVal.Remove(dbResult);
|
||||
|
||||
// 4. Salvo tutto
|
||||
return await _dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
|
||||
public async Task<GenValueModel?> GetByIdAsync(int Id) =>
|
||||
await _dbCtx.DbSetGenVal.FirstOrDefaultAsync(x => x.GenValID == Id);
|
||||
public async Task<GenValueModel?> GetByIdAsync(int Id)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetGenVal.FirstOrDefaultAsync(x => x.GenValID == Id);
|
||||
}
|
||||
|
||||
public async Task<List<GenValueModel>> GetFiltAsync(string codClass)
|
||||
{
|
||||
return await _dbCtx.DbSetGenVal
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetGenVal
|
||||
.Where(x => x.ClassCod == codClass)
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
@@ -58,56 +86,78 @@ namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
|
||||
public async Task<bool> MoveAsync(GenValueModel selRec, bool moveUp)
|
||||
{
|
||||
// 1. Recupero il record corrente
|
||||
var currRec = await _dbCtx.DbSetGenVal
|
||||
.FirstOrDefaultAsync(x => x.GenValID == selRec.GenValID);
|
||||
// Add validation for null entity
|
||||
if (selRec == null) return false;
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
|
||||
// 2. Numero totale record della classe
|
||||
int numRec = await _dbCtx.DbSetGenVal
|
||||
.CountAsync(x => x.ClassCod == selRec.ClassCod);
|
||||
// Wrap in transaction for atomicity (multi-row update - swap positions)
|
||||
await using var tx = await dbCtx.Database.BeginTransactionAsync();
|
||||
try
|
||||
{
|
||||
// 1. Recupero il record corrente
|
||||
var currRec = await dbCtx.DbSetGenVal
|
||||
.FirstOrDefaultAsync(x => x.GenValID == selRec.GenValID);
|
||||
|
||||
// 3. Calcolo nuova posizione
|
||||
int newPos = moveUp ? currRec.Index - 1 : currRec.Index + 1;
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
bool canMove = moveUp ? newPos > 0 : newPos <= numRec;
|
||||
if (!canMove)
|
||||
return false;
|
||||
// 2. Numero totale record della classe
|
||||
int numRec = await dbCtx.DbSetGenVal
|
||||
.CountAsync(x => x.ClassCod == selRec.ClassCod);
|
||||
|
||||
// 4. Recupero il record da scambiare
|
||||
var otherRec = await _dbCtx.DbSetGenVal
|
||||
.FirstOrDefaultAsync(x => x.ClassCod == selRec.ClassCod && x.Index == newPos);
|
||||
// 3. Calcolo nuova posizione
|
||||
int newPos = moveUp ? currRec.Index - 1 : currRec.Index + 1;
|
||||
|
||||
if (otherRec == null)
|
||||
return false;
|
||||
bool canMove = moveUp ? newPos > 0 : newPos <= numRec;
|
||||
if (!canMove)
|
||||
return false;
|
||||
|
||||
// 5. Swap indici
|
||||
otherRec.Index = currRec.Index;
|
||||
currRec.Index = newPos;
|
||||
// 4. Recupero il record da scambiare
|
||||
var otherRec = await dbCtx.DbSetGenVal
|
||||
.FirstOrDefaultAsync(x => x.ClassCod == selRec.ClassCod && x.Index == newPos);
|
||||
|
||||
_dbCtx.Entry(otherRec).State = EntityState.Modified;
|
||||
_dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
if (otherRec == null)
|
||||
return false;
|
||||
|
||||
// 6. Salvo
|
||||
return await _dbCtx.SaveChangesAsync() > 0;
|
||||
// 5. Swap indici
|
||||
otherRec.Index = currRec.Index;
|
||||
currRec.Index = newPos;
|
||||
|
||||
dbCtx.Entry(otherRec).State = EntityState.Modified;
|
||||
dbCtx.Entry(currRec).State = EntityState.Modified;
|
||||
|
||||
// 6. Salvo
|
||||
bool done = await dbCtx.SaveChangesAsync() > 0;
|
||||
|
||||
if (done)
|
||||
await tx.CommitAsync();
|
||||
|
||||
return done;
|
||||
}
|
||||
catch
|
||||
{
|
||||
await tx.RollbackAsync();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(GenValueModel entity)
|
||||
public async Task<bool> UpdateAsync(GenValueModel entity)
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
// Recuperiamo l'entità tracciata dal context
|
||||
var trackedEntity = _dbCtx.DbSetGenVal.Local.FirstOrDefault(x => x.GenValID == entity.GenValID);
|
||||
var trackedEntity = dbCtx.DbSetGenVal.FirstOrDefaultAsync(x => x.GenValID == entity.GenValID);
|
||||
|
||||
if (trackedEntity != null)
|
||||
{
|
||||
// Aggiorna i valori dell'entità tracciata con quelli della nuova
|
||||
_dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
dbCtx.Entry(trackedEntity).CurrentValues.SetValues(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbCtx.DbSetGenVal.Update(entity);
|
||||
dbCtx.DbSetGenVal.Update(entity);
|
||||
}
|
||||
return await dbCtx.SaveChangesAsync() > 0;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Utils;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public interface ICounterRepository
|
||||
{
|
||||
Task<List<CounterModel>> GetAllAsync(int? yearRef = null);
|
||||
|
||||
Task<int> GetNextAsync(int yearRef, string countName);
|
||||
}
|
||||
}
|
||||
@@ -6,17 +6,17 @@ namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
void Add(GenClassModel entity);
|
||||
Task<bool> AddAsync(GenClassModel entity);
|
||||
|
||||
Task<int> CountChildrenAsync(string classCod);
|
||||
|
||||
void Delete(GenClassModel entity);
|
||||
Task<bool> DeleteAsync(GenClassModel entity);
|
||||
|
||||
Task<List<GenClassModel>> GetAllWithNavAsync();
|
||||
Task<List<GenClassModel>> GetAllAsync();
|
||||
|
||||
Task<GenClassModel?> GetByCodeAsync(string code);
|
||||
|
||||
void Update(GenClassModel entity);
|
||||
Task<bool> UpdateAsync(GenClassModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
void Add(GenValueModel entity);
|
||||
Task<bool> AddAsync(GenValueModel entity);
|
||||
|
||||
Task<bool> DeleteAsync(GenValueModel entity);
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
|
||||
Task<bool> MoveAsync(GenValueModel selRec, bool moveUp);
|
||||
|
||||
void Update(GenValueModel entity);
|
||||
Task<bool> UpdateAsync(GenValueModel entity);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Utils;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public interface ITagRepository
|
||||
{
|
||||
Task<List<TagsModel>> GetAllAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Repository.Utils
|
||||
{
|
||||
public class TagRepository : BaseRepository, ITagRepository
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public TagRepository(IDbContextFactory<DataLayerContext> ctxFactory) : base(ctxFactory)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public async Task<List<TagsModel>> GetAllAsync()
|
||||
{
|
||||
await using var dbCtx = await CreateContextAsync();
|
||||
return await dbCtx.DbSetTags
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using EgwCoreLib.Lux.Data.Services.Internal;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using StackExchange.Redis;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
@@ -31,6 +33,13 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
_config = Configuration;
|
||||
_redisConn = RedisConn;
|
||||
_redisDb = _redisConn.GetDatabase();
|
||||
// configuro la base key x la cache Redis, con verifica contenga Cache finale
|
||||
_redisBaseKey = _config.GetValue<string>("ServerConf:RedisBaseKey") ?? "Lux:Cache";
|
||||
// aggiungo cache se non finisse per ":cache"
|
||||
if (!_redisBaseKey.EndsWith(":Cache"))
|
||||
{
|
||||
_redisBaseKey += ":Cache";
|
||||
}
|
||||
// setup tracing
|
||||
// Verifica conf trace...
|
||||
_traceEnabled = _config.GetValue<bool>("Otel:EnableTracing", false);
|
||||
@@ -116,7 +125,7 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
public MessagePipe PipeProfElement { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// Pipe dei messaggi per ritorno ProfileList calcolate da Engine di calcolo verso interfaccia utente.
|
||||
/// Pipe dei messaggi per ritorno ProfileListAsync calcolate da Engine di calcolo verso interfaccia utente.
|
||||
/// I messaggi vengono inviati sul canale Redis definito da ChannelProfList.
|
||||
/// </summary>
|
||||
public MessagePipe PipeProfList { get; set; } = null!;
|
||||
@@ -270,47 +279,6 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
}
|
||||
}
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Helper generale di lettura da cache o da funzione (DB) con caching successivo
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="key"></param>
|
||||
/// <param name="factory"></param>
|
||||
/// <param name="expiration"></param>
|
||||
/// <returns></returns>
|
||||
protected async Task<T> GetOrSetCacheAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiration = null)
|
||||
{
|
||||
using var activity = ActivitySource.StartActivity($"Cache:{key}");
|
||||
string source = "REDIS";
|
||||
|
||||
// 1. Tenta il recupero da Redis
|
||||
var rawData = await _redisDb.StringGetAsync(key);
|
||||
|
||||
if (rawData.HasValue)
|
||||
{
|
||||
activity?.SetTag("data.source", source);
|
||||
// LogTrace opzionale qui
|
||||
return JsonConvert.DeserializeObject<T>(rawData.ToString())!;
|
||||
}
|
||||
|
||||
// 2. Cache Miss: Esegui la funzione factory (di solito la query al DB)
|
||||
source = "DB";
|
||||
activity?.SetTag("data.source", source);
|
||||
|
||||
T result = await factory();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
// 3. Salva in Redis per la prossima volta
|
||||
var serialized = JsonConvert.SerializeObject(result, JSSettings);
|
||||
await _redisDb.StringSetAsync(key, serialized, expiration ?? LongCache);
|
||||
}
|
||||
|
||||
return result!;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Helper generale di lettura da cache o da funzione (DB) con caching successivo
|
||||
/// </summary>
|
||||
@@ -323,8 +291,6 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
{
|
||||
using var activity = StartActivity();
|
||||
string source = "DB";
|
||||
//// 🔍 Ricavo il nome del metodo chiamante dalla factory
|
||||
//string caller = factory.Method.DeclaringType?.Name + "." + factory.Method.Name;
|
||||
|
||||
// 1. Provo Redis
|
||||
var cached = await _redisDb.StringGetAsync(key);
|
||||
@@ -334,8 +300,7 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
var cachedResult = JsonConvert.DeserializeObject<T>(cached!)!;
|
||||
|
||||
activity?.SetTag("data.source", source);
|
||||
//LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
|
||||
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms", methodName: caller);
|
||||
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms", LogLevel.Trace, caller);
|
||||
|
||||
return cachedResult;
|
||||
}
|
||||
@@ -355,14 +320,11 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
activity?.Stop();
|
||||
|
||||
// log in console
|
||||
//LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms");
|
||||
LogTrace($"{source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds:N3}ms", methodName: caller);
|
||||
LogTrace($"GetOrSetCacheAsync | {source} | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds:N3}ms", LogLevel.Trace, caller);
|
||||
|
||||
//return value;
|
||||
return result!;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Helper trace messaggio log (SE abilitato)
|
||||
/// </summary>
|
||||
@@ -399,6 +361,8 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
}
|
||||
var result = await body(activity);
|
||||
activity?.SetStatus(ActivityStatusCode.Ok);
|
||||
activity?.Stop();
|
||||
LogTrace($"TraceAsync | trace: {activity?.TraceId} | {activity?.Duration.TotalMilliseconds}ms", methodName: name);
|
||||
return result;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -414,6 +378,8 @@ namespace EgwCoreLib.Lux.Data.Services
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private static readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new();
|
||||
|
||||
/// <summary>
|
||||
/// Durata della cache lunga in secondi (predefinito: 5 minuti)
|
||||
/// Utilizzato nella proprietà LongCache per definire quanto a lungo i dati devono essere memorizzati in cache.
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Services.Utils
|
||||
{
|
||||
public interface ITemplateRowService
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> CloneAsync(TemplateRowModel rec2clone);
|
||||
|
||||
Task<bool> DeleteAsync(TemplateRowModel model);
|
||||
|
||||
Task<List<string>> FixRowUidAsync(int templateId);
|
||||
|
||||
Task<List<TemplateRowModel>> GetAllAsync();
|
||||
|
||||
Task<List<TemplateRowModel>> GetByParentAsync(int templateId);
|
||||
|
||||
Task<bool> UpdateAwaitStateAsync(int templateRowId, bool? awaitBom, bool? awaitPrice, bool flushCache = false);
|
||||
|
||||
Task<bool> UpdateFileDataAsync(TemplateRowModel updRec);
|
||||
|
||||
Task<bool> UpdateSerStructAsync(int TemplateRowID, string serStruct);
|
||||
|
||||
Task<bool> UpsertAsync(TemplateRowModel upsRec);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Services.Utils
|
||||
{
|
||||
public interface ITemplateService
|
||||
{
|
||||
#region Public Methods
|
||||
|
||||
Task<bool> CloneAsync(TemplateModel rec2clone);
|
||||
|
||||
Task<bool> DeleteAsync(TemplateModel model);
|
||||
|
||||
Task<List<TemplateModel>> GetAllAsync();
|
||||
|
||||
Task<bool> UpsertAsync(TemplateModel upsRec);
|
||||
|
||||
Task<bool> UpdateCostAsync(int templateId);
|
||||
|
||||
#endregion Public Methods
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,303 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using EgwCoreLib.Lux.Data.Repository.Utils;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using StackExchange.Redis;
|
||||
using static EgwCoreLib.Lux.Core.Enums;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Services.Utils
|
||||
{
|
||||
public class TemplateRowService : BaseServ, ITemplateRowService
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public TemplateRowService(
|
||||
IConfiguration config,
|
||||
IConnectionMultiplexer redis,
|
||||
ITemplateRowRepository repo) : base(config, redis)
|
||||
{
|
||||
_className = "TemplateRow";
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Esegue il cloning completo di un Template e di TUTTE le relative righe...
|
||||
/// </summary>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CloneAsync(TemplateRowModel rec2clone)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Clone", async (activity) =>
|
||||
{
|
||||
// eseguo clone
|
||||
var result = await _repo.CloneAsync(rec2clone);
|
||||
|
||||
// se eseguito, pulisco la cache correlata
|
||||
if (result)
|
||||
{
|
||||
// Invalido sia la lista classi che eventuali dettagli correlati
|
||||
await ClearCacheAsync($"{_redisBaseKey}:Template:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione record
|
||||
/// </summary>
|
||||
/// <param name="rec2del"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> DeleteAsync(TemplateRowModel rec2del)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Delete", async (activity) =>
|
||||
{
|
||||
var dbResult = await _repo.GetRowAsync(rec2del.TemplateRowID);
|
||||
if (dbResult == null) return false;
|
||||
|
||||
bool success = await _repo.DeleteAsync(dbResult);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:Template:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua fix UID righe child del temoplate indicato e restituisce elenco UID da chiamare x refresh
|
||||
/// </summary>
|
||||
/// <param name="TemplateID">Key</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<string>> FixRowUidAsync(int templateId)
|
||||
{
|
||||
return await TraceAsync($"{_className}.FixRowUidAsync", async (activity) =>
|
||||
{
|
||||
// 1. Recupero righe
|
||||
var rows = await _repo.GetRowsAsync(templateId);
|
||||
|
||||
// 2. Trovo quelle da sistemare
|
||||
var list2fix = rows
|
||||
.Where(x => string.IsNullOrEmpty(x.TemplateRowUID) ||
|
||||
x.TemplateRowUID != x.TemplateRowDtx)
|
||||
.ToList();
|
||||
|
||||
// 3. Se non c’è nulla da fare → ritorno
|
||||
if (list2fix.Count == 0)
|
||||
return new List<string>();
|
||||
|
||||
// 4. Preparo la lista da restituire
|
||||
var result = list2fix
|
||||
.Select(x => x.TemplateRowDtx)
|
||||
.ToList();
|
||||
|
||||
// 5. Aggiorno i record
|
||||
foreach (var row in list2fix)
|
||||
row.TemplateRowUID = row.TemplateRowDtx;
|
||||
|
||||
// 6. Salvo
|
||||
bool success = await _repo.SaveRowsAsync(list2fix);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:Template:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco completo TemplateRow da DB
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<TemplateRowModel>> GetAllAsync()
|
||||
{
|
||||
return await TraceAsync($"{_className}.GetAll", async (activity) =>
|
||||
{
|
||||
return await GetOrSetCacheAsync(
|
||||
$"{_redisBaseKey}:{_className}:ALL",
|
||||
async () => await _repo.GetAllWithNavAsync(),
|
||||
UltraLongCache
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco filtrato (parent) TemplateRow da DB
|
||||
/// </summary>
|
||||
/// <param name="templateId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<TemplateRowModel>> GetByParentAsync(int templateId)
|
||||
{
|
||||
return await TraceAsync($"{_className}.GetByParent", async (activity) =>
|
||||
{
|
||||
return await GetOrSetCacheAsync(
|
||||
$"{_redisBaseKey}:{_className}:{templateId}",
|
||||
async () => await _repo.GetRowsAsync(templateId),
|
||||
LongCache
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task<bool> UpdateAwaitStateAsync(int templateRowId, bool? awaitBom, bool? awaitPrice, bool flushCache = false)
|
||||
{
|
||||
return await TraceAsync($"{_className}.UpdateAwaitState", async (activity) =>
|
||||
{
|
||||
var currRec = await _repo.GetRowAsync(templateRowId);
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
if (awaitBom.HasValue)
|
||||
currRec.AwaitBom = awaitBom.Value;
|
||||
|
||||
if (awaitPrice.HasValue)
|
||||
currRec.AwaitPrice = awaitPrice.Value;
|
||||
|
||||
//_repo.Update(currRec);
|
||||
|
||||
activity?.SetTag("db.operation", "UPDATE");
|
||||
|
||||
bool success = await _repo.UpdateAsync(currRec);
|
||||
|
||||
if (success && flushCache)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:Template:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua update delle info legate al file per il Template indicato
|
||||
/// </summary>
|
||||
/// <param name="updRec">Riga Template coi dati da aggiornare</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpdateFileDataAsync(TemplateRowModel updRec)
|
||||
{
|
||||
return await TraceAsync($"{_className}.UpdateFileData", async (activity) =>
|
||||
{
|
||||
var currRec = await _repo.GetRowAsync(updRec.TemplateRowID);
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
currRec.FileName = updRec.FileName;
|
||||
currRec.FileResource = updRec.FileResource;
|
||||
currRec.FileSize = updRec.FileSize;
|
||||
currRec.SerStruct = updRec.SerStruct;
|
||||
currRec.ImgType = Core.Enums.ImageType.Calculated;
|
||||
|
||||
//_repo.Update(currRec);
|
||||
|
||||
activity?.SetTag("db.operation", "UPDATE");
|
||||
|
||||
bool success = await _repo.UpdateAsync(currRec);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:Template:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua update del valore serializzato della Riga Template
|
||||
/// </summary>
|
||||
/// <param name="TemplateRowID">ID Riga Template da aggiornare</param>
|
||||
/// <param name="serStruct">Serializzazione oggetto (es JWD)</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpdateSerStructAsync(int TemplateRowID, string serStruct)
|
||||
{
|
||||
return await TraceAsync($"{_className}.UpdateSerStruct", async (activity) =>
|
||||
{
|
||||
var currRec = await _repo.GetRowAsync(TemplateRowID);
|
||||
|
||||
if (currRec == null)
|
||||
return false;
|
||||
|
||||
currRec.SerStruct = serStruct;
|
||||
currRec.ImgType = Core.Enums.ImageType.Calculated;
|
||||
|
||||
//_repo.Update(currRec);
|
||||
|
||||
activity?.SetTag("db.operation", "UPDATE");
|
||||
|
||||
bool success = await _repo.UpdateAsync(currRec);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:Template:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upsert record TemplateRow
|
||||
/// </summary>
|
||||
/// <param name="updRec"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpsertAsync(TemplateRowModel upsRec)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Upsert", async (activity) =>
|
||||
{
|
||||
// verifico imgType...
|
||||
if (upsRec.SellingItemNav != null && (upsRec.SellingItemNav.SourceType == ItemSourceType.Jwd || upsRec.SellingItemNav.SourceType == ItemSourceType.FileBTL))
|
||||
{
|
||||
upsRec.ImgType = ImageType.Calculated;
|
||||
}
|
||||
|
||||
// cerso sul DB
|
||||
var currRec = await _repo.GetRowAsync(upsRec.TemplateRowID);
|
||||
|
||||
string operation = "UPDATE";
|
||||
bool success = false;
|
||||
|
||||
if (currRec != null)
|
||||
{
|
||||
success = await _repo.UpdateAsync(upsRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
operation = "INSERT";
|
||||
success = await _repo.AddAsync(upsRec);
|
||||
}
|
||||
|
||||
activity?.SetTag("db.operation", operation);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:Template:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private readonly string _className;
|
||||
private readonly ITemplateRowRepository _repo;
|
||||
|
||||
#endregion Private Fields
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
using EgwCoreLib.Lux.Core.RestPayload;
|
||||
using EgwCoreLib.Lux.Data.DbModel.Catalog;
|
||||
using EgwCoreLib.Lux.Data.Domains;
|
||||
using EgwCoreLib.Lux.Data.Repository.Utils;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Newtonsoft.Json;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Services.Utils
|
||||
{
|
||||
public class TemplateService : BaseServ, ITemplateService
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public TemplateService(
|
||||
IConfiguration config,
|
||||
IConnectionMultiplexer redis,
|
||||
ITemplateRepository repo) : base(config, redis)
|
||||
{
|
||||
_className = "Template";
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Esegue il cloning completo di un Template e di TUTTE le relative righe...
|
||||
/// </summary>
|
||||
/// <param name="rec2clone"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> CloneAsync(TemplateModel rec2clone)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Clone", async (activity) =>
|
||||
{
|
||||
// eseguo clone
|
||||
var result = await _repo.CloneAsync(rec2clone);
|
||||
|
||||
// se eseguito, pulisco la cache correlata
|
||||
if (result)
|
||||
{
|
||||
// Invalido sia la lista classi che eventuali dettagli correlati
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:TemplateRows:*");
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione record
|
||||
/// </summary>
|
||||
/// <param name="rec2del"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> DeleteAsync(TemplateModel rec2del)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Delete", async (activity) =>
|
||||
{
|
||||
var dbResult = await _repo.GetByIdAsync(rec2del.TemplateID);
|
||||
if (dbResult == null) return false;
|
||||
|
||||
var numChild = await _repo.CountChildrenAsync(rec2del.TemplateID);
|
||||
|
||||
if (numChild > 0)
|
||||
{
|
||||
activity?.SetTag("delete.status", "rejected_has_children");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = await _repo.DeleteAsync(dbResult);
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:TemplateRows:*");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco completo Template da DB
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<TemplateModel>> GetAllAsync()
|
||||
{
|
||||
// Uso helper TraceAsync che gestisce automaticamente StartActivity, Log e Exception tracking
|
||||
return await TraceAsync($"{_className}.GetAll", async (activity) =>
|
||||
{
|
||||
return await GetOrSetCacheAsync(
|
||||
$"{_redisBaseKey}:{_className}:ALL",
|
||||
async () => await _repo.GetAllWithNavAsync()
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua update dei costi di tutte le righe del template indicato
|
||||
/// </summary>
|
||||
/// <param name="templateId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpdateCostAsync(int templateId)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Upsert", async (activity) =>
|
||||
{
|
||||
// 1. Recupero dati
|
||||
var rows = await _repo.GetRowsAsync(templateId);
|
||||
var itemGroups = await _repo.GetItemGroupsAsync();
|
||||
var bomItems = await _repo.GetBomItemsAsync();
|
||||
|
||||
// 2. Calcolo costi BOM
|
||||
foreach (var row in rows)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(row.ItemBOM) && row.ItemBOM.Length > 2)
|
||||
{
|
||||
var bomList = JsonConvert.DeserializeObject<List<BomItemDTO>>(row.ItemBOM);
|
||||
if (bomList != null)
|
||||
{
|
||||
double totCost = 0;
|
||||
double totPrice = 0;
|
||||
int totItemQty = 0;
|
||||
int numGroupOk = 0;
|
||||
int numItemOk = 0;
|
||||
|
||||
BomCalculator.Validate(
|
||||
itemGroups,
|
||||
bomItems,
|
||||
ref bomList,
|
||||
null,
|
||||
ref totCost,
|
||||
ref totPrice,
|
||||
ref totItemQty,
|
||||
ref numGroupOk,
|
||||
ref numItemOk
|
||||
);
|
||||
|
||||
row.ItemBOM = JsonConvert.SerializeObject(bomList);
|
||||
row.BomCost = Math.Round(totCost, 3);
|
||||
row.BomPrice = Math.Round(totPrice, 3);
|
||||
row.BomOk = bomList.Count == numGroupOk;
|
||||
row.ItemOk = bomList.Count == numItemOk;
|
||||
row.ProdItemQty = totItemQty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Salvo
|
||||
var result = await _repo.SaveRowsAsync(rows);
|
||||
|
||||
if (result)
|
||||
{
|
||||
// 4. Invalido cache
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:TemplateRows:*");
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upsert record Template
|
||||
/// </summary>
|
||||
/// <param name="updRec"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpsertAsync(TemplateModel upsRec)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Upsert", async (activity) =>
|
||||
{
|
||||
var currRec = await _repo.GetByIdAsync(upsRec.TemplateID);
|
||||
|
||||
string operation = "UPDATE";
|
||||
bool success = false;
|
||||
if (currRec != null)
|
||||
{
|
||||
success = await _repo.UpdateAsync(upsRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
operation = "INSERT";
|
||||
success = await _repo.AddAsync(upsRec);
|
||||
}
|
||||
|
||||
activity?.SetTag("db.operation", operation);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}:*");
|
||||
await ClearCacheAsync($"{_redisBaseKey}:TemplateRows:*");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private readonly string _className;
|
||||
private readonly ITemplateRepository _repo;
|
||||
|
||||
#endregion Private Fields
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using EgwCoreLib.Lux.Data.DbModel.Config;
|
||||
using EgwCoreLib.Lux.Data.Repository.Config;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace EgwCoreLib.Lux.Data.Services.Config
|
||||
{
|
||||
public class ConfGlassService : BaseServ, IConfGlassService
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
public ConfGlassService(
|
||||
IConfiguration config,
|
||||
IConnectionMultiplexer redis,
|
||||
IConfGlassRepository repo) : base(config, redis)
|
||||
{
|
||||
_className = "ConfGlass";
|
||||
_repo = repo;
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Eliminazione record
|
||||
/// </summary>
|
||||
/// <param name="rec2del"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> DeleteAsync(GlassModel rec2del)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Delete", async (activity) =>
|
||||
{
|
||||
var dbResult = await _repo.GetByIdAsync(rec2del.GlassID);
|
||||
if (dbResult == null) return false;
|
||||
|
||||
// 3. Eseguo la cancellazione
|
||||
bool success = await _repo.DeleteAsync(dbResult);
|
||||
|
||||
// 4. Se ha avuto successo, pulisco la cache
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elenco completo Glass da DB
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<List<GlassModel>> GetAllAsync()
|
||||
{
|
||||
// Uso helper TraceAsync che gestisce automaticamente StartActivity, Log e Exception tracking
|
||||
return await TraceAsync($"{_className}.GetAll", async (activity) =>
|
||||
{
|
||||
return await GetOrSetCacheAsync(
|
||||
$"{_redisBaseKey}:{_className}:ALL",
|
||||
async () => await _repo.GetAllAsync(),
|
||||
UltraLongCache
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Upsert record Glass (aggiorna o inserisce)
|
||||
/// </summary>
|
||||
/// <param name="upsRec"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UpsertAsync(GlassModel upsRec)
|
||||
{
|
||||
return await TraceAsync($"{_className}.Upsert", async (activity) =>
|
||||
{
|
||||
var currRec = await _repo.GetByIdAsync(upsRec.GlassID);
|
||||
|
||||
string operation = "UPDATE";
|
||||
bool success = false;
|
||||
if (currRec != null)
|
||||
{
|
||||
upsRec.Code = string.IsNullOrEmpty(upsRec.Code) ? $"{upsRec.GlassID:0000}" : upsRec.Code;
|
||||
success = await _repo.UpdateAsync(upsRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
operation = "INSERT";
|
||||
success = await _repo.AddAsync(upsRec);
|
||||
}
|
||||
|
||||
activity?.SetTag("db.operation", operation);
|
||||
|
||||
if (success)
|
||||
{
|
||||
await ClearCacheAsync($"{_redisBaseKey}:{_className}");
|
||||
}
|
||||
|
||||
return success;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
private readonly string _className;
|
||||
private readonly IConfGlassRepository _repo;
|
||||
|
||||
#endregion Private Fields
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user