refactor: Migrate backend and frontend architecture from a module-based to an app-based structure.
This commit is contained in:
@@ -30,3 +30,5 @@ File riassuntivo dello stato di sviluppo di Zentral.
|
|||||||
- Refactoring Report Designer in modulo autonomo e abilitazione stampa PDF condizionale.
|
- Refactoring Report Designer in modulo autonomo e abilitazione stampa PDF condizionale.
|
||||||
- [2025-12-04 Fix Report Designer Imports](./devlog/2025-12-04-212500_fix_report_designer_imports.md) - **Completato**
|
- [2025-12-04 Fix Report Designer Imports](./devlog/2025-12-04-212500_fix_report_designer_imports.md) - **Completato**
|
||||||
- Correzione import path nel modulo Report Designer e registrazione modulo nel backend.
|
- Correzione import path nel modulo Report Designer e registrazione modulo nel backend.
|
||||||
|
- [2025-12-05 Rename Modules to Apps](./devlog/2025-12-05-194100_rename_modules_to_apps.md) - **Completato**
|
||||||
|
- Rinomina terminologia "Modulo" in "Applicazione" (App) su Backend e Frontend.
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Rename Modules to Apps
|
||||||
|
|
||||||
|
**Stato:** Completato
|
||||||
|
**Data:** 2025-12-05
|
||||||
|
|
||||||
|
## Descrizione
|
||||||
|
Rinomina completa della terminologia "Modulo" (Module) in "Applicazione" (App) in tutto il progetto (Backend, Frontend, Database).
|
||||||
|
|
||||||
|
## Modifiche Apportate
|
||||||
|
|
||||||
|
### Backend
|
||||||
|
- Rinominate entità `AppModule` -> `App`, `ModuleSubscription` -> `AppSubscription`.
|
||||||
|
- Rinominate tabelle database `AppModules` -> `Apps`, `ModuleSubscriptions` -> `AppSubscriptions`.
|
||||||
|
- Rinominati servizi `ModuleService` -> `AppService`.
|
||||||
|
- Rinominati controller `ModulesController` -> `AppsController`.
|
||||||
|
- Aggiornati namespace da `Zentral.API.Modules` a `Zentral.API.Apps`.
|
||||||
|
- Aggiornate rotte API da `api/modules` a `api/apps`.
|
||||||
|
- Creata e applicata migrazione `RenameModulesToApps`.
|
||||||
|
|
||||||
|
### Frontend
|
||||||
|
- Rinominate directory `src/frontend/src/modules` -> `src/frontend/src/apps`.
|
||||||
|
- Rinominati file e componenti principali (es. `ModuleContext` -> `AppContext`, `ModulesAdminPage` -> `AppsAdminPage`).
|
||||||
|
- Aggiornati tutti i riferimenti nel codice (variabili, interfacce, hook).
|
||||||
|
- Aggiornati i file di traduzione (i18n) per usare "Applicazione" invece di "Modulo".
|
||||||
|
|
||||||
|
### Documentazione
|
||||||
|
- Aggiornato `docs/development/development-folders.md` con la nuova struttura.
|
||||||
|
- Aggiornato `docs/development/ZENTRAL.md`.
|
||||||
|
|
||||||
|
## Note
|
||||||
|
- La build del frontend è passata con successo.
|
||||||
|
- Il backend è stato aggiornato e la migrazione applicata.
|
||||||
@@ -3,7 +3,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.HR.Controllers;
|
namespace Zentral.API.Apps.HR.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/hr/[controller]")]
|
[Route("api/hr/[controller]")]
|
||||||
@@ -3,7 +3,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.HR.Controllers;
|
namespace Zentral.API.Apps.HR.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/hr/[controller]")]
|
[Route("api/hr/[controller]")]
|
||||||
@@ -3,7 +3,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.HR.Controllers;
|
namespace Zentral.API.Apps.HR.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/hr/[controller]")]
|
[Route("api/hr/[controller]")]
|
||||||
@@ -3,7 +3,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.HR.Controllers;
|
namespace Zentral.API.Apps.HR.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/hr/[controller]")]
|
[Route("api/hr/[controller]")]
|
||||||
@@ -3,7 +3,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.HR.Controllers;
|
namespace Zentral.API.Apps.HR.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/hr/[controller]")]
|
[Route("api/hr/[controller]")]
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.API.Modules.Production.Services;
|
using Zentral.API.Apps.Production.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Controllers;
|
namespace Zentral.API.Apps.Production.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/production/bom")]
|
[Route("api/production/bom")]
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.API.Modules.Production.Services;
|
using Zentral.API.Apps.Production.Services;
|
||||||
using Zentral.Domain.Entities.Production;
|
using Zentral.Domain.Entities.Production;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Controllers;
|
namespace Zentral.API.Apps.Production.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/production/mrp")]
|
[Route("api/production/mrp")]
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.API.Modules.Production.Services;
|
using Zentral.API.Apps.Production.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Controllers;
|
namespace Zentral.API.Apps.Production.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/production/cycles")]
|
[Route("api/production/cycles")]
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.API.Modules.Production.Services;
|
using Zentral.API.Apps.Production.Services;
|
||||||
using Zentral.Domain.Entities.Production;
|
using Zentral.Domain.Entities.Production;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Controllers;
|
namespace Zentral.API.Apps.Production.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/production/orders")]
|
[Route("api/production/orders")]
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.API.Modules.Production.Services;
|
using Zentral.API.Apps.Production.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Controllers;
|
namespace Zentral.API.Apps.Production.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/production/work-centers")]
|
[Route("api/production/work-centers")]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class BillOfMaterialsDto
|
public class BillOfMaterialsDto
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class CreateBillOfMaterialsDto
|
public class CreateBillOfMaterialsDto
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class CreateProductionOrderDto
|
public class CreateProductionOrderDto
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class MrpConfigurationDto
|
public class MrpConfigurationDto
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class ProductionCycleDto
|
public class ProductionCycleDto
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Zentral.Domain.Entities.Production;
|
using Zentral.Domain.Entities.Production;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class ProductionOrderDto
|
public class ProductionOrderDto
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class UpdateBillOfMaterialsDto
|
public class UpdateBillOfMaterialsDto
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Zentral.Domain.Entities.Production;
|
using Zentral.Domain.Entities.Production;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class UpdateProductionOrderDto
|
public class UpdateProductionOrderDto
|
||||||
{
|
{
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
namespace Zentral.API.Modules.Production.Dtos;
|
namespace Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
public class WorkCenterDto
|
public class WorkCenterDto
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.Domain.Entities.Production;
|
using Zentral.Domain.Entities.Production;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Services;
|
namespace Zentral.API.Apps.Production.Services;
|
||||||
|
|
||||||
public interface IMrpService
|
public interface IMrpService
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.Domain.Entities.Production;
|
using Zentral.Domain.Entities.Production;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Services;
|
namespace Zentral.API.Apps.Production.Services;
|
||||||
|
|
||||||
public interface IProductionService
|
public interface IProductionService
|
||||||
{
|
{
|
||||||
@@ -2,9 +2,9 @@ using Zentral.Domain.Entities.Production;
|
|||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Zentral.Infrastructure.Data;
|
using Zentral.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Services;
|
namespace Zentral.API.Apps.Production.Services;
|
||||||
|
|
||||||
public class MrpService : IMrpService
|
public class MrpService : IMrpService
|
||||||
{
|
{
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
using Zentral.API.Modules.Production.Dtos;
|
using Zentral.API.Apps.Production.Dtos;
|
||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Production;
|
using Zentral.Domain.Entities.Production;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Zentral.Infrastructure.Data;
|
using Zentral.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Production.Services;
|
namespace Zentral.API.Apps.Production.Services;
|
||||||
|
|
||||||
public class ProductionService : IProductionService
|
public class ProductionService : IProductionService
|
||||||
{
|
{
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Zentral.API.Modules.Purchases.Dtos;
|
using Zentral.API.Apps.Purchases.Dtos;
|
||||||
using Zentral.API.Modules.Purchases.Services;
|
using Zentral.API.Apps.Purchases.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Purchases.Controllers;
|
namespace Zentral.API.Apps.Purchases.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/purchases/orders")]
|
[Route("api/purchases/orders")]
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Zentral.API.Modules.Purchases.Dtos;
|
using Zentral.API.Apps.Purchases.Dtos;
|
||||||
using Zentral.API.Modules.Purchases.Services;
|
using Zentral.API.Apps.Purchases.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Purchases.Controllers;
|
namespace Zentral.API.Apps.Purchases.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/purchases/suppliers")]
|
[Route("api/purchases/suppliers")]
|
||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Zentral.Domain.Entities.Purchases;
|
using Zentral.Domain.Entities.Purchases;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Purchases.Dtos;
|
namespace Zentral.API.Apps.Purchases.Dtos;
|
||||||
|
|
||||||
public class PurchaseOrderDto
|
public class PurchaseOrderDto
|
||||||
{
|
{
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Purchases.Dtos;
|
namespace Zentral.API.Apps.Purchases.Dtos;
|
||||||
|
|
||||||
public class SupplierDto
|
public class SupplierDto
|
||||||
{
|
{
|
||||||
@@ -2,15 +2,15 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Zentral.API.Modules.Purchases.Dtos;
|
using Zentral.API.Apps.Purchases.Dtos;
|
||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.API.Services;
|
using Zentral.API.Services;
|
||||||
using Zentral.Domain.Entities.Purchases;
|
using Zentral.Domain.Entities.Purchases;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Zentral.Infrastructure.Data;
|
using Zentral.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Purchases.Services;
|
namespace Zentral.API.Apps.Purchases.Services;
|
||||||
|
|
||||||
public class PurchaseService
|
public class PurchaseService
|
||||||
{
|
{
|
||||||
@@ -2,13 +2,13 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Zentral.API.Modules.Purchases.Dtos;
|
using Zentral.API.Apps.Purchases.Dtos;
|
||||||
using Zentral.API.Services;
|
using Zentral.API.Services;
|
||||||
using Zentral.Domain.Entities.Purchases;
|
using Zentral.Domain.Entities.Purchases;
|
||||||
using Zentral.Infrastructure.Data;
|
using Zentral.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Purchases.Services;
|
namespace Zentral.API.Apps.Purchases.Services;
|
||||||
|
|
||||||
public class SupplierService
|
public class SupplierService
|
||||||
{
|
{
|
||||||
@@ -4,7 +4,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.ReportDesigner.Controllers;
|
namespace Zentral.API.Apps.ReportDesigner.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/report-designer/resources")]
|
[Route("api/report-designer/resources")]
|
||||||
@@ -4,7 +4,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.ReportDesigner.Controllers;
|
namespace Zentral.API.Apps.ReportDesigner.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/report-designer/templates")]
|
[Route("api/report-designer/templates")]
|
||||||
@@ -4,7 +4,7 @@ using Zentral.Infrastructure.Data;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.ReportDesigner.Controllers;
|
namespace Zentral.API.Apps.ReportDesigner.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/report-designer/reports")]
|
[Route("api/report-designer/reports")]
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Zentral.API.Modules.Sales.Dtos;
|
using Zentral.API.Apps.Sales.Dtos;
|
||||||
using Zentral.API.Modules.Sales.Services;
|
using Zentral.API.Apps.Sales.Services;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Sales.Controllers;
|
namespace Zentral.API.Apps.Sales.Controllers;
|
||||||
|
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/sales/orders")]
|
[Route("api/sales/orders")]
|
||||||
@@ -2,7 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Zentral.Domain.Entities.Sales;
|
using Zentral.Domain.Entities.Sales;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Sales.Dtos;
|
namespace Zentral.API.Apps.Sales.Dtos;
|
||||||
|
|
||||||
public class SalesOrderDto
|
public class SalesOrderDto
|
||||||
{
|
{
|
||||||
@@ -2,15 +2,15 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Zentral.API.Modules.Sales.Dtos;
|
using Zentral.API.Apps.Sales.Dtos;
|
||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.API.Services;
|
using Zentral.API.Services;
|
||||||
using Zentral.Domain.Entities.Sales;
|
using Zentral.Domain.Entities.Sales;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Zentral.Infrastructure.Data;
|
using Zentral.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Sales.Services;
|
namespace Zentral.API.Apps.Sales.Services;
|
||||||
|
|
||||||
public class SalesService
|
public class SalesService
|
||||||
{
|
{
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione delle partite/lotti
|
/// Controller per la gestione delle partite/lotti
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione degli inventari fisici
|
/// Controller per la gestione degli inventari fisici
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione dei seriali/matricole
|
/// Controller per la gestione dei seriali/matricole
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione delle giacenze e valorizzazione
|
/// Controller per la gestione delle giacenze e valorizzazione
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione dei movimenti di magazzino
|
/// Controller per la gestione dei movimenti di magazzino
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione degli articoli di magazzino
|
/// Controller per la gestione degli articoli di magazzino
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione delle categorie articoli
|
/// Controller per la gestione delle categorie articoli
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Controllers;
|
namespace Zentral.API.Apps.Warehouse.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione dei magazzini
|
/// Controller per la gestione dei magazzini
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
using Zentral.Domain.Entities.Warehouse;
|
using Zentral.Domain.Entities.Warehouse;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Services;
|
namespace Zentral.API.Apps.Warehouse.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interfaccia servizio principale per il modulo Magazzino
|
/// Interfaccia servizio principale per il modulo Magazzino
|
||||||
@@ -6,7 +6,7 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
|
|
||||||
using Zentral.API.Hubs;
|
using Zentral.API.Hubs;
|
||||||
|
|
||||||
namespace Zentral.API.Modules.Warehouse.Services;
|
namespace Zentral.API.Apps.Warehouse.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implementazione del servizio principale per il modulo Magazzino
|
/// Implementazione del servizio principale per il modulo Magazzino
|
||||||
@@ -5,87 +5,87 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
namespace Zentral.API.Controllers;
|
namespace Zentral.API.Controllers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Controller per la gestione dei moduli applicativi e delle subscription
|
/// Controller per la gestione delle applicazioni e delle subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ApiController]
|
[ApiController]
|
||||||
[Route("api/[controller]")]
|
[Route("api/[controller]")]
|
||||||
public class ModulesController : ControllerBase
|
public class AppsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ModuleService _moduleService;
|
private readonly AppService _appService;
|
||||||
private readonly ILogger<ModulesController> _logger;
|
private readonly ILogger<AppsController> _logger;
|
||||||
|
|
||||||
public ModulesController(ModuleService moduleService, ILogger<ModulesController> logger)
|
public AppsController(AppService appService, ILogger<AppsController> logger)
|
||||||
{
|
{
|
||||||
_moduleService = moduleService;
|
_appService = appService;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene tutti i moduli disponibili con stato subscription
|
/// Ottiene tutte le applicazioni disponibili con stato subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult<List<ModuleDto>>> GetAllModules()
|
public async Task<ActionResult<List<AppDto>>> GetAllApps()
|
||||||
{
|
{
|
||||||
var modules = await _moduleService.GetAllModulesAsync();
|
var apps = await _appService.GetAllAppsAsync();
|
||||||
return Ok(modules.Select(MapToDto).ToList());
|
return Ok(apps.Select(MapToDto).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene solo i moduli attivi (per costruzione menu)
|
/// Ottiene solo le applicazioni attive (per costruzione menu)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet("active")]
|
[HttpGet("active")]
|
||||||
public async Task<ActionResult<List<ModuleDto>>> GetActiveModules()
|
public async Task<ActionResult<List<AppDto>>> GetActiveApps()
|
||||||
{
|
{
|
||||||
var modules = await _moduleService.GetActiveModulesAsync();
|
var apps = await _appService.GetActiveAppsAsync();
|
||||||
return Ok(modules.Select(MapToDto).ToList());
|
return Ok(apps.Select(MapToDto).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene un modulo specifico per codice
|
/// Ottiene un'applicazione specifica per codice
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet("{code}")]
|
[HttpGet("{code}")]
|
||||||
public async Task<ActionResult<ModuleDto>> GetModule(string code)
|
public async Task<ActionResult<AppDto>> GetApp(string code)
|
||||||
{
|
{
|
||||||
var module = await _moduleService.GetModuleByCodeAsync(code);
|
var app = await _appService.GetAppByCodeAsync(code);
|
||||||
if (module == null)
|
if (app == null)
|
||||||
return NotFound(new { message = $"Modulo '{code}' non trovato" });
|
return NotFound(new { message = $"Applicazione '{code}' non trovata" });
|
||||||
|
|
||||||
return Ok(MapToDto(module));
|
return Ok(MapToDto(app));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifica se un modulo è abilitato
|
/// Verifica se un'applicazione è abilitata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet("{code}/enabled")]
|
[HttpGet("{code}/enabled")]
|
||||||
public async Task<ActionResult<ModuleStatusDto>> IsModuleEnabled(string code)
|
public async Task<ActionResult<AppStatusDto>> IsAppEnabled(string code)
|
||||||
{
|
{
|
||||||
var module = await _moduleService.GetModuleByCodeAsync(code);
|
var app = await _appService.GetAppByCodeAsync(code);
|
||||||
if (module == null)
|
if (app == null)
|
||||||
return NotFound(new { message = $"Modulo '{code}' non trovato" });
|
return NotFound(new { message = $"Applicazione '{code}' non trovata" });
|
||||||
|
|
||||||
var isEnabled = await _moduleService.IsModuleEnabledAsync(code);
|
var isEnabled = await _appService.IsAppEnabledAsync(code);
|
||||||
var hasValidSubscription = await _moduleService.HasValidSubscriptionAsync(code);
|
var hasValidSubscription = await _appService.HasValidSubscriptionAsync(code);
|
||||||
|
|
||||||
return Ok(new ModuleStatusDto
|
return Ok(new AppStatusDto
|
||||||
{
|
{
|
||||||
Code = code,
|
Code = code,
|
||||||
IsEnabled = isEnabled,
|
IsEnabled = isEnabled,
|
||||||
HasValidSubscription = hasValidSubscription,
|
HasValidSubscription = hasValidSubscription,
|
||||||
IsCore = module.IsCore,
|
IsCore = app.IsCore,
|
||||||
DaysRemaining = module.Subscription?.GetDaysRemaining(),
|
DaysRemaining = app.Subscription?.GetDaysRemaining(),
|
||||||
IsExpiringSoon = module.Subscription?.IsExpiringSoon() ?? false
|
IsExpiringSoon = app.Subscription?.IsExpiringSoon() ?? false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attiva un modulo
|
/// Attiva un'applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPut("{code}/enable")]
|
[HttpPut("{code}/enable")]
|
||||||
public async Task<ActionResult<SubscriptionDto>> EnableModule(string code, [FromBody] EnableModuleRequest request)
|
public async Task<ActionResult<AppSubscriptionDto>> EnableApp(string code, [FromBody] EnableAppRequest request)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var subscription = await _moduleService.EnableModuleAsync(
|
var subscription = await _appService.EnableAppAsync(
|
||||||
code,
|
code,
|
||||||
request.SubscriptionType,
|
request.SubscriptionType,
|
||||||
request.StartDate,
|
request.StartDate,
|
||||||
@@ -107,15 +107,15 @@ public class ModulesController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disattiva un modulo
|
/// Disattiva un'applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPut("{code}/disable")]
|
[HttpPut("{code}/disable")]
|
||||||
public async Task<ActionResult> DisableModule(string code)
|
public async Task<ActionResult> DisableApp(string code)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _moduleService.DisableModuleAsync(code);
|
await _appService.DisableAppAsync(code);
|
||||||
return Ok(new { message = $"Modulo '{code}' disattivato" });
|
return Ok(new { message = $"Applicazione '{code}' disattivata" });
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
{
|
{
|
||||||
@@ -131,21 +131,21 @@ public class ModulesController : ControllerBase
|
|||||||
/// Ottiene tutte le subscription
|
/// Ottiene tutte le subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet("subscriptions")]
|
[HttpGet("subscriptions")]
|
||||||
public async Task<ActionResult<List<SubscriptionDto>>> GetAllSubscriptions()
|
public async Task<ActionResult<List<AppSubscriptionDto>>> GetAllAppSubscriptions()
|
||||||
{
|
{
|
||||||
var subscriptions = await _moduleService.GetAllSubscriptionsAsync();
|
var subscriptions = await _appService.GetAllSubscriptionsAsync();
|
||||||
return Ok(subscriptions.Select(MapSubscriptionToDto).ToList());
|
return Ok(subscriptions.Select(MapSubscriptionToDto).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Aggiorna la subscription di un modulo
|
/// Aggiorna la subscription di un'applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPut("{code}/subscription")]
|
[HttpPut("{code}/subscription")]
|
||||||
public async Task<ActionResult<SubscriptionDto>> UpdateSubscription(string code, [FromBody] UpdateSubscriptionRequest request)
|
public async Task<ActionResult<AppSubscriptionDto>> UpdateAppSubscription(string code, [FromBody] UpdateAppSubscriptionRequest request)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var subscription = await _moduleService.UpdateSubscriptionAsync(
|
var subscription = await _appService.UpdateSubscriptionAsync(
|
||||||
code,
|
code,
|
||||||
request.SubscriptionType,
|
request.SubscriptionType,
|
||||||
request.EndDate,
|
request.EndDate,
|
||||||
@@ -165,14 +165,14 @@ public class ModulesController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rinnova la subscription di un modulo
|
/// Rinnova la subscription di un'applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPost("{code}/subscription/renew")]
|
[HttpPost("{code}/subscription/renew")]
|
||||||
public async Task<ActionResult<SubscriptionDto>> RenewSubscription(string code, [FromBody] RenewSubscriptionRequest? request = null)
|
public async Task<ActionResult<AppSubscriptionDto>> RenewAppSubscription(string code, [FromBody] RenewAppSubscriptionRequest? request = null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var subscription = await _moduleService.RenewSubscriptionAsync(code, request?.PaidPrice);
|
var subscription = await _appService.RenewSubscriptionAsync(code, request?.PaidPrice);
|
||||||
return Ok(MapSubscriptionToDto(subscription));
|
return Ok(MapSubscriptionToDto(subscription));
|
||||||
}
|
}
|
||||||
catch (ArgumentException ex)
|
catch (ArgumentException ex)
|
||||||
@@ -186,77 +186,77 @@ public class ModulesController : ControllerBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene i moduli in scadenza
|
/// Ottiene le applicazioni in scadenza
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpGet("expiring")]
|
[HttpGet("expiring")]
|
||||||
public async Task<ActionResult<List<ModuleDto>>> GetExpiringModules([FromQuery] int daysThreshold = 30)
|
public async Task<ActionResult<List<AppDto>>> GetExpiringApps([FromQuery] int daysThreshold = 30)
|
||||||
{
|
{
|
||||||
var modules = await _moduleService.GetExpiringModulesAsync(daysThreshold);
|
var apps = await _appService.GetExpiringAppsAsync(daysThreshold);
|
||||||
return Ok(modules.Select(MapToDto).ToList());
|
return Ok(apps.Select(MapToDto).ToList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inizializza i moduli di default (per setup iniziale)
|
/// Inizializza le applicazioni di default (per setup iniziale)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPost("seed")]
|
[HttpPost("seed")]
|
||||||
public async Task<ActionResult> SeedDefaultModules()
|
public async Task<ActionResult> SeedDefaultApps()
|
||||||
{
|
{
|
||||||
await _moduleService.SeedDefaultModulesAsync();
|
await _appService.SeedDefaultAppsAsync();
|
||||||
return Ok(new { message = "Moduli di default inizializzati" });
|
return Ok(new { message = "Applicazioni di default inizializzate" });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Forza il controllo delle subscription scadute
|
/// Forza il controllo delle subscription scadute
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPost("check-expired")]
|
[HttpPost("check-expired")]
|
||||||
public async Task<ActionResult> CheckExpiredSubscriptions()
|
public async Task<ActionResult> CheckExpiredAppSubscriptions()
|
||||||
{
|
{
|
||||||
var count = await _moduleService.CheckExpiredSubscriptionsAsync();
|
var count = await _appService.CheckExpiredSubscriptionsAsync();
|
||||||
return Ok(new { message = $"Controllate le subscription, {count} moduli disattivati per scadenza" });
|
return Ok(new { message = $"Controllate le subscription, {count} applicazioni disattivate per scadenza" });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalida la cache dei moduli
|
/// Invalida la cache delle applicazioni
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[HttpPost("invalidate-cache")]
|
[HttpPost("invalidate-cache")]
|
||||||
public ActionResult InvalidateCache()
|
public ActionResult InvalidateAppsCache()
|
||||||
{
|
{
|
||||||
_moduleService.InvalidateCache();
|
_appService.InvalidateCache();
|
||||||
return Ok(new { message = "Cache moduli invalidata" });
|
return Ok(new { message = "Cache applicazioni invalidata" });
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Mapping
|
#region Mapping
|
||||||
|
|
||||||
private static ModuleDto MapToDto(AppModule module)
|
private static AppDto MapToDto(App app)
|
||||||
{
|
{
|
||||||
return new ModuleDto
|
return new AppDto
|
||||||
{
|
{
|
||||||
Id = module.Id,
|
Id = app.Id,
|
||||||
Code = module.Code,
|
Code = app.Code,
|
||||||
Name = module.Name,
|
Name = app.Name,
|
||||||
Description = module.Description,
|
Description = app.Description,
|
||||||
Icon = module.Icon,
|
Icon = app.Icon,
|
||||||
BasePrice = module.BasePrice,
|
BasePrice = app.BasePrice,
|
||||||
MonthlyPrice = module.GetMonthlyPrice(),
|
MonthlyPrice = app.GetMonthlyPrice(),
|
||||||
MonthlyMultiplier = module.MonthlyMultiplier,
|
MonthlyMultiplier = app.MonthlyMultiplier,
|
||||||
SortOrder = module.SortOrder,
|
SortOrder = app.SortOrder,
|
||||||
IsCore = module.IsCore,
|
IsCore = app.IsCore,
|
||||||
Dependencies = module.GetDependencies().ToList(),
|
Dependencies = app.GetDependencies().ToList(),
|
||||||
RoutePath = module.RoutePath,
|
RoutePath = app.RoutePath,
|
||||||
IsAvailable = module.IsAvailable,
|
IsAvailable = app.IsAvailable,
|
||||||
IsEnabled = module.IsCore || ((module.Subscription?.IsEnabled ?? false) && (module.Subscription?.IsValid() ?? false)),
|
IsEnabled = app.IsCore || ((app.Subscription?.IsEnabled ?? false) && (app.Subscription?.IsValid() ?? false)),
|
||||||
Subscription = module.Subscription != null ? MapSubscriptionToDto(module.Subscription) : null
|
Subscription = app.Subscription != null ? MapSubscriptionToDto(app.Subscription) : null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SubscriptionDto MapSubscriptionToDto(ModuleSubscription subscription)
|
private static AppSubscriptionDto MapSubscriptionToDto(AppSubscription subscription)
|
||||||
{
|
{
|
||||||
return new SubscriptionDto
|
return new AppSubscriptionDto
|
||||||
{
|
{
|
||||||
Id = subscription.Id,
|
Id = subscription.Id,
|
||||||
ModuleId = subscription.ModuleId,
|
AppId = subscription.AppId,
|
||||||
ModuleCode = subscription.Module?.Code,
|
AppCode = subscription.App?.Code,
|
||||||
ModuleName = subscription.Module?.Name,
|
AppName = subscription.App?.Name,
|
||||||
IsEnabled = subscription.IsEnabled,
|
IsEnabled = subscription.IsEnabled,
|
||||||
SubscriptionType = subscription.SubscriptionType,
|
SubscriptionType = subscription.SubscriptionType,
|
||||||
SubscriptionTypeName = subscription.SubscriptionType.ToString(),
|
SubscriptionTypeName = subscription.SubscriptionType.ToString(),
|
||||||
@@ -277,7 +277,7 @@ public class ModulesController : ControllerBase
|
|||||||
|
|
||||||
#region DTOs
|
#region DTOs
|
||||||
|
|
||||||
public class ModuleDto
|
public class AppDto
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public string Code { get; set; } = string.Empty;
|
public string Code { get; set; } = string.Empty;
|
||||||
@@ -293,15 +293,15 @@ public class ModuleDto
|
|||||||
public string? RoutePath { get; set; }
|
public string? RoutePath { get; set; }
|
||||||
public bool IsAvailable { get; set; }
|
public bool IsAvailable { get; set; }
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
public SubscriptionDto? Subscription { get; set; }
|
public AppSubscriptionDto? Subscription { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SubscriptionDto
|
public class AppSubscriptionDto
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int ModuleId { get; set; }
|
public int AppId { get; set; }
|
||||||
public string? ModuleCode { get; set; }
|
public string? AppCode { get; set; }
|
||||||
public string? ModuleName { get; set; }
|
public string? AppName { get; set; }
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
public SubscriptionType SubscriptionType { get; set; }
|
public SubscriptionType SubscriptionType { get; set; }
|
||||||
public string SubscriptionTypeName { get; set; } = string.Empty;
|
public string SubscriptionTypeName { get; set; } = string.Empty;
|
||||||
@@ -316,7 +316,7 @@ public class SubscriptionDto
|
|||||||
public bool IsExpiringSoon { get; set; }
|
public bool IsExpiringSoon { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ModuleStatusDto
|
public class AppStatusDto
|
||||||
{
|
{
|
||||||
public string Code { get; set; } = string.Empty;
|
public string Code { get; set; } = string.Empty;
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
@@ -326,7 +326,7 @@ public class ModuleStatusDto
|
|||||||
public bool IsExpiringSoon { get; set; }
|
public bool IsExpiringSoon { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class EnableModuleRequest
|
public class EnableAppRequest
|
||||||
{
|
{
|
||||||
public SubscriptionType SubscriptionType { get; set; } = SubscriptionType.Annual;
|
public SubscriptionType SubscriptionType { get; set; } = SubscriptionType.Annual;
|
||||||
public DateTime? StartDate { get; set; }
|
public DateTime? StartDate { get; set; }
|
||||||
@@ -336,7 +336,7 @@ public class EnableModuleRequest
|
|||||||
public string? Notes { get; set; }
|
public string? Notes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UpdateSubscriptionRequest
|
public class UpdateAppSubscriptionRequest
|
||||||
{
|
{
|
||||||
public SubscriptionType? SubscriptionType { get; set; }
|
public SubscriptionType? SubscriptionType { get; set; }
|
||||||
public DateTime? EndDate { get; set; }
|
public DateTime? EndDate { get; set; }
|
||||||
@@ -344,7 +344,7 @@ public class UpdateSubscriptionRequest
|
|||||||
public string? Notes { get; set; }
|
public string? Notes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RenewSubscriptionRequest
|
public class RenewAppSubscriptionRequest
|
||||||
{
|
{
|
||||||
public decimal? PaidPrice { get; set; }
|
public decimal? PaidPrice { get; set; }
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,10 @@ using Zentral.API.Hubs;
|
|||||||
using Zentral.API.Services;
|
using Zentral.API.Services;
|
||||||
// Trigger rebuild
|
// Trigger rebuild
|
||||||
using Zentral.API.Services.Reports;
|
using Zentral.API.Services.Reports;
|
||||||
using Zentral.API.Modules.Warehouse.Services;
|
using Zentral.API.Apps.Warehouse.Services;
|
||||||
using Zentral.API.Modules.Purchases.Services;
|
using Zentral.API.Apps.Purchases.Services;
|
||||||
using Zentral.API.Modules.Sales.Services;
|
using Zentral.API.Apps.Sales.Services;
|
||||||
using Zentral.API.Modules.Production.Services;
|
using Zentral.API.Apps.Production.Services;
|
||||||
using Zentral.Infrastructure.Data;
|
using Zentral.Infrastructure.Data;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
@@ -22,7 +22,7 @@ builder.Services.AddDbContext<ZentralDbContext>(options =>
|
|||||||
builder.Services.AddScoped<EventoCostiService>();
|
builder.Services.AddScoped<EventoCostiService>();
|
||||||
builder.Services.AddScoped<DemoDataService>();
|
builder.Services.AddScoped<DemoDataService>();
|
||||||
builder.Services.AddScoped<ReportGeneratorService>();
|
builder.Services.AddScoped<ReportGeneratorService>();
|
||||||
builder.Services.AddScoped<ModuleService>();
|
builder.Services.AddScoped<AppService>();
|
||||||
builder.Services.AddScoped<AutoCodeService>();
|
builder.Services.AddScoped<AutoCodeService>();
|
||||||
builder.Services.AddScoped<CustomFieldService>();
|
builder.Services.AddScoped<CustomFieldService>();
|
||||||
builder.Services.AddSingleton<DataNotificationService>();
|
builder.Services.AddSingleton<DataNotificationService>();
|
||||||
@@ -110,9 +110,14 @@ using (var scope = app.Services.CreateScope())
|
|||||||
// Seed data (only in development or if database is empty)
|
// Seed data (only in development or if database is empty)
|
||||||
DbSeeder.Seed(db);
|
DbSeeder.Seed(db);
|
||||||
|
|
||||||
// Seed default modules
|
// Seed default apps
|
||||||
var moduleService = scope.ServiceProvider.GetRequiredService<ModuleService>();
|
var appService = scope.ServiceProvider.GetRequiredService<AppService>();
|
||||||
await moduleService.SeedDefaultModulesAsync();
|
await appService.SeedDefaultAppsAsync();
|
||||||
|
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
await appService.SeedDevSubscriptionsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
// Seed warehouse default data
|
// Seed warehouse default data
|
||||||
var warehouseService = scope.ServiceProvider.GetRequiredService<IWarehouseService>();
|
var warehouseService = scope.ServiceProvider.GetRequiredService<IWarehouseService>();
|
||||||
|
|||||||
@@ -6,22 +6,22 @@ using Microsoft.Extensions.Caching.Memory;
|
|||||||
namespace Zentral.API.Services;
|
namespace Zentral.API.Services;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Service per la gestione dei moduli applicativi e delle relative subscription
|
/// Service per la gestione delle applicazioni e delle relative subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ModuleService
|
public class AppService
|
||||||
{
|
{
|
||||||
private readonly ZentralDbContext _context;
|
private readonly ZentralDbContext _context;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly ILogger<ModuleService> _logger;
|
private readonly ILogger<AppService> _logger;
|
||||||
|
|
||||||
private const string MODULES_CACHE_KEY = "modules_all";
|
private const string APPS_CACHE_KEY = "apps_all";
|
||||||
private const string ACTIVE_MODULES_CACHE_KEY = "modules_active";
|
private const string ACTIVE_APPS_CACHE_KEY = "apps_active";
|
||||||
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(5);
|
private static readonly TimeSpan CacheDuration = TimeSpan.FromMinutes(5);
|
||||||
|
|
||||||
public ModuleService(
|
public AppService(
|
||||||
ZentralDbContext context,
|
ZentralDbContext context,
|
||||||
IMemoryCache cache,
|
IMemoryCache cache,
|
||||||
ILogger<ModuleService> logger)
|
ILogger<AppService> logger)
|
||||||
{
|
{
|
||||||
_context = context;
|
_context = context;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
@@ -29,80 +29,80 @@ public class ModuleService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene tutti i moduli con lo stato della subscription
|
/// Ottiene tutte le applicazioni con lo stato della subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<List<AppModule>> GetAllModulesAsync()
|
public async Task<List<App>> GetAllAppsAsync()
|
||||||
{
|
{
|
||||||
return await _cache.GetOrCreateAsync(MODULES_CACHE_KEY, async entry =>
|
return await _cache.GetOrCreateAsync(APPS_CACHE_KEY, async entry =>
|
||||||
{
|
{
|
||||||
entry.AbsoluteExpirationRelativeToNow = CacheDuration;
|
entry.AbsoluteExpirationRelativeToNow = CacheDuration;
|
||||||
return await _context.AppModules
|
return await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.Where(m => m.IsAvailable)
|
.Where(m => m.IsAvailable)
|
||||||
.OrderBy(m => m.SortOrder)
|
.OrderBy(m => m.SortOrder)
|
||||||
.ThenBy(m => m.Name)
|
.ThenBy(m => m.Name)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}) ?? new List<AppModule>();
|
}) ?? new List<App>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene solo i moduli attivi (per la costruzione del menu)
|
/// Ottiene solo le applicazioni attive (per la costruzione del menu)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<List<AppModule>> GetActiveModulesAsync()
|
public async Task<List<App>> GetActiveAppsAsync()
|
||||||
{
|
{
|
||||||
return await _cache.GetOrCreateAsync(ACTIVE_MODULES_CACHE_KEY, async entry =>
|
return await _cache.GetOrCreateAsync(ACTIVE_APPS_CACHE_KEY, async entry =>
|
||||||
{
|
{
|
||||||
entry.AbsoluteExpirationRelativeToNow = CacheDuration;
|
entry.AbsoluteExpirationRelativeToNow = CacheDuration;
|
||||||
var modules = await _context.AppModules
|
var apps = await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.Where(m => m.IsAvailable)
|
.Where(m => m.IsAvailable)
|
||||||
.OrderBy(m => m.SortOrder)
|
.OrderBy(m => m.SortOrder)
|
||||||
.ThenBy(m => m.Name)
|
.ThenBy(m => m.Name)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
return modules.Where(m => m.IsCore || ((m.Subscription?.IsEnabled ?? false) && (m.Subscription?.IsValid() ?? false))).ToList();
|
return apps.Where(m => m.IsCore || ((m.Subscription?.IsEnabled ?? false) && (m.Subscription?.IsValid() ?? false))).ToList();
|
||||||
}) ?? new List<AppModule>();
|
}) ?? new List<App>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene un modulo specifico per codice
|
/// Ottiene un'applicazione specifica per codice
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<AppModule?> GetModuleByCodeAsync(string code)
|
public async Task<App?> GetAppByCodeAsync(string code)
|
||||||
{
|
{
|
||||||
return await _context.AppModules
|
return await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.FirstOrDefaultAsync(m => m.Code == code);
|
.FirstOrDefaultAsync(m => m.Code == code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifica se un modulo è attualmente abilitato
|
/// Verifica se un'applicazione è attualmente abilitata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<bool> IsModuleEnabledAsync(string code)
|
public async Task<bool> IsAppEnabledAsync(string code)
|
||||||
{
|
{
|
||||||
var module = await GetModuleByCodeAsync(code);
|
var app = await GetAppByCodeAsync(code);
|
||||||
if (module == null)
|
if (app == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// I moduli core sono sempre abilitati
|
// Le applicazioni core sono sempre abilitate
|
||||||
if (module.IsCore)
|
if (app.IsCore)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return (module.Subscription?.IsEnabled ?? false) && (module.Subscription?.IsValid() ?? false);
|
return (app.Subscription?.IsEnabled ?? false) && (app.Subscription?.IsValid() ?? false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifica se un modulo ha una subscription valida (non scaduta)
|
/// Verifica se un'applicazione ha una subscription valida (non scaduta)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<bool> HasValidSubscriptionAsync(string code)
|
public async Task<bool> HasValidSubscriptionAsync(string code)
|
||||||
{
|
{
|
||||||
var module = await GetModuleByCodeAsync(code);
|
var app = await GetAppByCodeAsync(code);
|
||||||
return module?.Subscription?.IsValid() ?? false;
|
return app?.Subscription?.IsValid() ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attiva un modulo creando o aggiornando la subscription
|
/// Attiva un'applicazione creando o aggiornando la subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<ModuleSubscription> EnableModuleAsync(
|
public async Task<AppSubscription> EnableAppAsync(
|
||||||
string code,
|
string code,
|
||||||
SubscriptionType subscriptionType,
|
SubscriptionType subscriptionType,
|
||||||
DateTime? startDate = null,
|
DateTime? startDate = null,
|
||||||
@@ -111,21 +111,21 @@ public class ModuleService
|
|||||||
decimal? paidPrice = null,
|
decimal? paidPrice = null,
|
||||||
string? notes = null)
|
string? notes = null)
|
||||||
{
|
{
|
||||||
var module = await _context.AppModules
|
var app = await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.FirstOrDefaultAsync(m => m.Code == code);
|
.FirstOrDefaultAsync(m => m.Code == code);
|
||||||
|
|
||||||
if (module == null)
|
if (app == null)
|
||||||
throw new ArgumentException($"Modulo con codice '{code}' non trovato");
|
throw new ArgumentException($"Applicazione con codice '{code}' non trovata");
|
||||||
|
|
||||||
if (module.IsCore)
|
if (app.IsCore)
|
||||||
throw new InvalidOperationException("I moduli core non possono essere attivati/disattivati manualmente");
|
throw new InvalidOperationException("Le applicazioni core non possono essere attivate/disattivate manualmente");
|
||||||
|
|
||||||
// Verifica dipendenze
|
// Verifica dipendenze
|
||||||
var missingDeps = await CheckDependenciesAsync(module);
|
var missingDeps = await CheckDependenciesAsync(app);
|
||||||
if (missingDeps.Any())
|
if (missingDeps.Any())
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"Il modulo richiede i seguenti moduli attivi: {string.Join(", ", missingDeps)}");
|
$"L'applicazione richiede le seguenti applicazioni attive: {string.Join(", ", missingDeps)}");
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var effectiveStartDate = startDate ?? now;
|
var effectiveStartDate = startDate ?? now;
|
||||||
@@ -142,178 +142,178 @@ public class ModuleService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (module.Subscription == null)
|
if (app.Subscription == null)
|
||||||
{
|
{
|
||||||
// Crea nuova subscription
|
// Crea nuova subscription
|
||||||
module.Subscription = new ModuleSubscription
|
app.Subscription = new AppSubscription
|
||||||
{
|
{
|
||||||
ModuleId = module.Id,
|
AppId = app.Id,
|
||||||
IsEnabled = true,
|
IsEnabled = true,
|
||||||
SubscriptionType = subscriptionType,
|
SubscriptionType = subscriptionType,
|
||||||
StartDate = effectiveStartDate,
|
StartDate = effectiveStartDate,
|
||||||
EndDate = effectiveEndDate,
|
EndDate = effectiveEndDate,
|
||||||
AutoRenew = autoRenew,
|
AutoRenew = autoRenew,
|
||||||
PaidPrice = paidPrice ?? module.BasePrice,
|
PaidPrice = paidPrice ?? app.BasePrice,
|
||||||
Notes = notes,
|
Notes = notes,
|
||||||
CreatedAt = now,
|
CreatedAt = now,
|
||||||
UpdatedAt = now
|
UpdatedAt = now
|
||||||
};
|
};
|
||||||
_context.ModuleSubscriptions.Add(module.Subscription);
|
_context.AppSubscriptions.Add(app.Subscription);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Aggiorna subscription esistente
|
// Aggiorna subscription esistente
|
||||||
module.Subscription.IsEnabled = true;
|
app.Subscription.IsEnabled = true;
|
||||||
module.Subscription.SubscriptionType = subscriptionType;
|
app.Subscription.SubscriptionType = subscriptionType;
|
||||||
module.Subscription.StartDate = effectiveStartDate;
|
app.Subscription.StartDate = effectiveStartDate;
|
||||||
module.Subscription.EndDate = effectiveEndDate;
|
app.Subscription.EndDate = effectiveEndDate;
|
||||||
module.Subscription.AutoRenew = autoRenew;
|
app.Subscription.AutoRenew = autoRenew;
|
||||||
module.Subscription.PaidPrice = paidPrice ?? module.Subscription.PaidPrice ?? module.BasePrice;
|
app.Subscription.PaidPrice = paidPrice ?? app.Subscription.PaidPrice ?? app.BasePrice;
|
||||||
if (notes != null) module.Subscription.Notes = notes;
|
if (notes != null) app.Subscription.Notes = notes;
|
||||||
module.Subscription.UpdatedAt = now;
|
app.Subscription.UpdatedAt = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
InvalidateCache();
|
InvalidateCache();
|
||||||
|
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Modulo {ModuleCode} attivato con subscription {Type} fino a {EndDate}",
|
"Applicazione {AppCode} attivata con subscription {Type} fino a {EndDate}",
|
||||||
code, subscriptionType, effectiveEndDate);
|
code, subscriptionType, effectiveEndDate);
|
||||||
|
|
||||||
return module.Subscription;
|
return app.Subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disattiva un modulo (mantiene i dati ma rimuove l'accesso)
|
/// Disattiva un'applicazione (mantiene i dati ma rimuove l'accesso)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task DisableModuleAsync(string code)
|
public async Task DisableAppAsync(string code)
|
||||||
{
|
{
|
||||||
var module = await _context.AppModules
|
var app = await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.FirstOrDefaultAsync(m => m.Code == code);
|
.FirstOrDefaultAsync(m => m.Code == code);
|
||||||
|
|
||||||
if (module == null)
|
if (app == null)
|
||||||
throw new ArgumentException($"Modulo con codice '{code}' non trovato");
|
throw new ArgumentException($"Applicazione con codice '{code}' non trovata");
|
||||||
|
|
||||||
if (module.IsCore)
|
if (app.IsCore)
|
||||||
throw new InvalidOperationException("I moduli core non possono essere disattivati");
|
throw new InvalidOperationException("Le applicazioni core non possono essere disattivate");
|
||||||
|
|
||||||
// Verifica se altri moduli dipendono da questo
|
// Verifica se altre applicazioni dipendono da questa
|
||||||
var dependentModules = await GetDependentModulesAsync(code);
|
var dependentApps = await GetDependentAppsAsync(code);
|
||||||
var activeDependents = dependentModules.Where(m => (m.Subscription?.IsEnabled ?? false) && (m.Subscription?.IsValid() ?? false)).ToList();
|
var activeDependents = dependentApps.Where(m => (m.Subscription?.IsEnabled ?? false) && (m.Subscription?.IsValid() ?? false)).ToList();
|
||||||
if (activeDependents.Any())
|
if (activeDependents.Any())
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"I seguenti moduli attivi dipendono da questo modulo: {string.Join(", ", activeDependents.Select(m => m.Name))}");
|
$"Le seguenti applicazioni attive dipendono da questa applicazione: {string.Join(", ", activeDependents.Select(m => m.Name))}");
|
||||||
|
|
||||||
if (module.Subscription != null)
|
if (app.Subscription != null)
|
||||||
{
|
{
|
||||||
module.Subscription.IsEnabled = false;
|
app.Subscription.IsEnabled = false;
|
||||||
module.Subscription.UpdatedAt = DateTime.UtcNow;
|
app.Subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidateCache();
|
InvalidateCache();
|
||||||
_logger.LogInformation("Modulo {ModuleCode} disattivato", code);
|
_logger.LogInformation("Applicazione {AppCode} disattivata", code);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Aggiorna i dettagli della subscription
|
/// Aggiorna i dettagli della subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<ModuleSubscription> UpdateSubscriptionAsync(
|
public async Task<AppSubscription> UpdateSubscriptionAsync(
|
||||||
string code,
|
string code,
|
||||||
SubscriptionType? subscriptionType = null,
|
SubscriptionType? subscriptionType = null,
|
||||||
DateTime? endDate = null,
|
DateTime? endDate = null,
|
||||||
bool? autoRenew = null,
|
bool? autoRenew = null,
|
||||||
string? notes = null)
|
string? notes = null)
|
||||||
{
|
{
|
||||||
var module = await _context.AppModules
|
var app = await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.FirstOrDefaultAsync(m => m.Code == code);
|
.FirstOrDefaultAsync(m => m.Code == code);
|
||||||
|
|
||||||
if (module == null)
|
if (app == null)
|
||||||
throw new ArgumentException($"Modulo con codice '{code}' non trovato");
|
throw new ArgumentException($"Applicazione con codice '{code}' non trovata");
|
||||||
|
|
||||||
if (module.Subscription == null)
|
if (app.Subscription == null)
|
||||||
throw new InvalidOperationException($"Il modulo '{code}' non ha una subscription attiva");
|
throw new InvalidOperationException($"L'applicazione '{code}' non ha una subscription attiva");
|
||||||
|
|
||||||
if (subscriptionType.HasValue)
|
if (subscriptionType.HasValue)
|
||||||
module.Subscription.SubscriptionType = subscriptionType.Value;
|
app.Subscription.SubscriptionType = subscriptionType.Value;
|
||||||
if (endDate.HasValue)
|
if (endDate.HasValue)
|
||||||
module.Subscription.EndDate = endDate.Value;
|
app.Subscription.EndDate = endDate.Value;
|
||||||
if (autoRenew.HasValue)
|
if (autoRenew.HasValue)
|
||||||
module.Subscription.AutoRenew = autoRenew.Value;
|
app.Subscription.AutoRenew = autoRenew.Value;
|
||||||
if (notes != null)
|
if (notes != null)
|
||||||
module.Subscription.Notes = notes;
|
app.Subscription.Notes = notes;
|
||||||
|
|
||||||
module.Subscription.UpdatedAt = DateTime.UtcNow;
|
app.Subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
InvalidateCache();
|
InvalidateCache();
|
||||||
|
|
||||||
return module.Subscription;
|
return app.Subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rinnova una subscription esistente
|
/// Rinnova una subscription esistente
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<ModuleSubscription> RenewSubscriptionAsync(string code, decimal? paidPrice = null)
|
public async Task<AppSubscription> RenewSubscriptionAsync(string code, decimal? paidPrice = null)
|
||||||
{
|
{
|
||||||
var module = await _context.AppModules
|
var app = await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.FirstOrDefaultAsync(m => m.Code == code);
|
.FirstOrDefaultAsync(m => m.Code == code);
|
||||||
|
|
||||||
if (module == null)
|
if (app == null)
|
||||||
throw new ArgumentException($"Modulo con codice '{code}' non trovato");
|
throw new ArgumentException($"Applicazione con codice '{code}' non trovata");
|
||||||
|
|
||||||
if (module.Subscription == null)
|
if (app.Subscription == null)
|
||||||
throw new InvalidOperationException($"Il modulo '{code}' non ha una subscription da rinnovare");
|
throw new InvalidOperationException($"L'applicazione '{code}' non ha una subscription da rinnovare");
|
||||||
|
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var currentEnd = module.Subscription.EndDate ?? now;
|
var currentEnd = app.Subscription.EndDate ?? now;
|
||||||
var newStart = currentEnd > now ? currentEnd : now;
|
var newStart = currentEnd > now ? currentEnd : now;
|
||||||
|
|
||||||
var newEnd = module.Subscription.SubscriptionType switch
|
var newEnd = app.Subscription.SubscriptionType switch
|
||||||
{
|
{
|
||||||
SubscriptionType.Monthly => newStart.AddMonths(1),
|
SubscriptionType.Monthly => newStart.AddMonths(1),
|
||||||
SubscriptionType.Annual => newStart.AddYears(1),
|
SubscriptionType.Annual => newStart.AddYears(1),
|
||||||
_ => newStart.AddYears(1) // Default to annual
|
_ => newStart.AddYears(1) // Default to annual
|
||||||
};
|
};
|
||||||
|
|
||||||
module.Subscription.StartDate = newStart;
|
app.Subscription.StartDate = newStart;
|
||||||
module.Subscription.EndDate = newEnd;
|
app.Subscription.EndDate = newEnd;
|
||||||
module.Subscription.LastRenewalDate = now;
|
app.Subscription.LastRenewalDate = now;
|
||||||
module.Subscription.IsEnabled = true;
|
app.Subscription.IsEnabled = true;
|
||||||
module.Subscription.PaidPrice = paidPrice ?? module.Subscription.PaidPrice;
|
app.Subscription.PaidPrice = paidPrice ?? app.Subscription.PaidPrice;
|
||||||
module.Subscription.UpdatedAt = now;
|
app.Subscription.UpdatedAt = now;
|
||||||
|
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
InvalidateCache();
|
InvalidateCache();
|
||||||
|
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"Modulo {ModuleCode} rinnovato fino a {EndDate}",
|
"Applicazione {AppCode} rinnovata fino a {EndDate}",
|
||||||
code, newEnd);
|
code, newEnd);
|
||||||
|
|
||||||
return module.Subscription;
|
return app.Subscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene tutte le subscription
|
/// Ottiene tutte le subscription
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<List<ModuleSubscription>> GetAllSubscriptionsAsync()
|
public async Task<List<AppSubscription>> GetAllSubscriptionsAsync()
|
||||||
{
|
{
|
||||||
return await _context.ModuleSubscriptions
|
return await _context.AppSubscriptions
|
||||||
.Include(s => s.Module)
|
.Include(s => s.App)
|
||||||
.OrderBy(s => s.Module.SortOrder)
|
.OrderBy(s => s.App.SortOrder)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifica e disattiva i moduli con subscription scaduta (per job schedulato)
|
/// Verifica e disattiva le applicazioni con subscription scaduta (per job schedulato)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<int> CheckExpiredSubscriptionsAsync()
|
public async Task<int> CheckExpiredSubscriptionsAsync()
|
||||||
{
|
{
|
||||||
var expiredSubscriptions = await _context.ModuleSubscriptions
|
var expiredSubscriptions = await _context.AppSubscriptions
|
||||||
.Include(s => s.Module)
|
.Include(s => s.App)
|
||||||
.Where(s => s.IsEnabled &&
|
.Where(s => s.IsEnabled &&
|
||||||
s.EndDate.HasValue &&
|
s.EndDate.HasValue &&
|
||||||
s.EndDate.Value < DateTime.UtcNow &&
|
s.EndDate.Value < DateTime.UtcNow &&
|
||||||
@@ -325,8 +325,8 @@ public class ModuleService
|
|||||||
subscription.IsEnabled = false;
|
subscription.IsEnabled = false;
|
||||||
subscription.UpdatedAt = DateTime.UtcNow;
|
subscription.UpdatedAt = DateTime.UtcNow;
|
||||||
_logger.LogWarning(
|
_logger.LogWarning(
|
||||||
"Modulo {ModuleCode} disattivato per scadenza subscription",
|
"Applicazione {AppCode} disattivata per scadenza subscription",
|
||||||
subscription.Module.Code);
|
subscription.App.Code);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expiredSubscriptions.Any())
|
if (expiredSubscriptions.Any())
|
||||||
@@ -339,13 +339,13 @@ public class ModuleService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene i moduli in scadenza entro N giorni
|
/// Ottiene le applicazioni in scadenza entro N giorni
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<List<AppModule>> GetExpiringModulesAsync(int daysThreshold = 30)
|
public async Task<List<App>> GetExpiringAppsAsync(int daysThreshold = 30)
|
||||||
{
|
{
|
||||||
var thresholdDate = DateTime.UtcNow.AddDays(daysThreshold);
|
var thresholdDate = DateTime.UtcNow.AddDays(daysThreshold);
|
||||||
|
|
||||||
return await _context.AppModules
|
return await _context.Apps
|
||||||
.Include(m => m.Subscription)
|
.Include(m => m.Subscription)
|
||||||
.Where(m => m.Subscription != null &&
|
.Where(m => m.Subscription != null &&
|
||||||
m.Subscription.IsEnabled &&
|
m.Subscription.IsEnabled &&
|
||||||
@@ -357,11 +357,11 @@ public class ModuleService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifica le dipendenze mancanti per un modulo
|
/// Verifica le dipendenze mancanti per un'applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task<List<string>> CheckDependenciesAsync(AppModule module)
|
private async Task<List<string>> CheckDependenciesAsync(App app)
|
||||||
{
|
{
|
||||||
var dependencies = module.GetDependencies().ToList();
|
var dependencies = app.GetDependencies().ToList();
|
||||||
if (!dependencies.Any())
|
if (!dependencies.Any())
|
||||||
return new List<string>();
|
return new List<string>();
|
||||||
|
|
||||||
@@ -369,10 +369,10 @@ public class ModuleService
|
|||||||
|
|
||||||
foreach (var depCode in dependencies)
|
foreach (var depCode in dependencies)
|
||||||
{
|
{
|
||||||
if (!await IsModuleEnabledAsync(depCode))
|
if (!await IsAppEnabledAsync(depCode))
|
||||||
{
|
{
|
||||||
var depModule = await GetModuleByCodeAsync(depCode);
|
var depApp = await GetAppByCodeAsync(depCode);
|
||||||
missingDeps.Add(depModule?.Name ?? depCode);
|
missingDeps.Add(depApp?.Name ?? depCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,34 +380,34 @@ public class ModuleService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Ottiene i moduli che dipendono da un determinato modulo
|
/// Ottiene le applicazioni che dipendono da una determinata applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task<List<AppModule>> GetDependentModulesAsync(string code)
|
private async Task<List<App>> GetDependentAppsAsync(string code)
|
||||||
{
|
{
|
||||||
var allModules = await GetAllModulesAsync();
|
var allApps = await GetAllAppsAsync();
|
||||||
return allModules
|
return allApps
|
||||||
.Where(m => m.GetDependencies().Contains(code))
|
.Where(m => m.GetDependencies().Contains(code))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invalida la cache dei moduli
|
/// Invalida la cache delle applicazioni
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void InvalidateCache()
|
public void InvalidateCache()
|
||||||
{
|
{
|
||||||
_cache.Remove(MODULES_CACHE_KEY);
|
_cache.Remove(APPS_CACHE_KEY);
|
||||||
_cache.Remove(ACTIVE_MODULES_CACHE_KEY);
|
_cache.Remove(ACTIVE_APPS_CACHE_KEY);
|
||||||
_logger.LogDebug("Cache moduli invalidata");
|
_logger.LogDebug("Cache applicazioni invalidata");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Inizializza i moduli di default se non esistono
|
/// Inizializza le applicazioni di default se non esistono
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task SeedDefaultModulesAsync()
|
public async Task SeedDefaultAppsAsync()
|
||||||
{
|
{
|
||||||
var defaultModules = new List<AppModule>
|
var defaultApps = new List<App>
|
||||||
{
|
{
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "warehouse",
|
Code = "warehouse",
|
||||||
Name = "Magazzino",
|
Name = "Magazzino",
|
||||||
@@ -421,7 +421,7 @@ public class ModuleService
|
|||||||
IsAvailable = true,
|
IsAvailable = true,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
},
|
},
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "purchases",
|
Code = "purchases",
|
||||||
Name = "Acquisti",
|
Name = "Acquisti",
|
||||||
@@ -436,7 +436,7 @@ public class ModuleService
|
|||||||
IsAvailable = true,
|
IsAvailable = true,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
},
|
},
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "sales",
|
Code = "sales",
|
||||||
Name = "Vendite",
|
Name = "Vendite",
|
||||||
@@ -451,7 +451,7 @@ public class ModuleService
|
|||||||
IsAvailable = true,
|
IsAvailable = true,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
},
|
},
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "production",
|
Code = "production",
|
||||||
Name = "Produzione",
|
Name = "Produzione",
|
||||||
@@ -466,7 +466,7 @@ public class ModuleService
|
|||||||
IsAvailable = true,
|
IsAvailable = true,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
},
|
},
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "quality",
|
Code = "quality",
|
||||||
Name = "Qualità",
|
Name = "Qualità",
|
||||||
@@ -480,7 +480,7 @@ public class ModuleService
|
|||||||
IsAvailable = true,
|
IsAvailable = true,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
},
|
},
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "events",
|
Code = "events",
|
||||||
Name = "Gestione Eventi",
|
Name = "Gestione Eventi",
|
||||||
@@ -494,7 +494,7 @@ public class ModuleService
|
|||||||
IsAvailable = true,
|
IsAvailable = true,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
},
|
},
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "hr",
|
Code = "hr",
|
||||||
Name = "Gestione Personale",
|
Name = "Gestione Personale",
|
||||||
@@ -508,7 +508,7 @@ public class ModuleService
|
|||||||
IsAvailable = true,
|
IsAvailable = true,
|
||||||
CreatedAt = DateTime.UtcNow
|
CreatedAt = DateTime.UtcNow
|
||||||
},
|
},
|
||||||
new AppModule
|
new App
|
||||||
{
|
{
|
||||||
Code = "report-designer",
|
Code = "report-designer",
|
||||||
Name = "Report Designer",
|
Name = "Report Designer",
|
||||||
@@ -524,15 +524,64 @@ public class ModuleService
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var existingCodes = await _context.AppModules.Select(m => m.Code).ToListAsync();
|
var existingCodes = await _context.Apps.Select(m => m.Code).ToListAsync();
|
||||||
var newModules = defaultModules.Where(m => !existingCodes.Contains(m.Code)).ToList();
|
var newApps = defaultApps.Where(m => !existingCodes.Contains(m.Code)).ToList();
|
||||||
|
|
||||||
if (newModules.Any())
|
if (newApps.Any())
|
||||||
{
|
{
|
||||||
_context.AppModules.AddRange(newModules);
|
_context.Apps.AddRange(newApps);
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
_logger.LogInformation("Added {Count} new default modules: {Modules}",
|
_logger.LogInformation("Added {Count} new default apps: {Apps}",
|
||||||
newModules.Count, string.Join(", ", newModules.Select(m => m.Code)));
|
newApps.Count, string.Join(", ", newApps.Select(m => m.Code)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attiva tutte le applicazioni per ambiente di sviluppo
|
||||||
|
/// </summary>
|
||||||
|
public async Task SeedDevSubscriptionsAsync()
|
||||||
|
{
|
||||||
|
var apps = await _context.Apps
|
||||||
|
.Include(a => a.Subscription)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var now = DateTime.UtcNow;
|
||||||
|
bool changes = false;
|
||||||
|
|
||||||
|
foreach (var app in apps)
|
||||||
|
{
|
||||||
|
if (app.Subscription == null)
|
||||||
|
{
|
||||||
|
app.Subscription = new AppSubscription
|
||||||
|
{
|
||||||
|
AppId = app.Id,
|
||||||
|
IsEnabled = true,
|
||||||
|
SubscriptionType = SubscriptionType.Annual,
|
||||||
|
StartDate = now,
|
||||||
|
EndDate = now.AddYears(1),
|
||||||
|
AutoRenew = true,
|
||||||
|
PaidPrice = 0,
|
||||||
|
Notes = "Auto-generated for Development",
|
||||||
|
CreatedAt = now,
|
||||||
|
UpdatedAt = now
|
||||||
|
};
|
||||||
|
_context.AppSubscriptions.Add(app.Subscription);
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
else if (!app.Subscription.IsEnabled)
|
||||||
|
{
|
||||||
|
app.Subscription.IsEnabled = true;
|
||||||
|
app.Subscription.EndDate = now.AddYears(1);
|
||||||
|
app.Subscription.UpdatedAt = now;
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changes)
|
||||||
|
{
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
InvalidateCache();
|
||||||
|
_logger.LogInformation("Dev subscriptions seeded for all apps");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,23 @@
|
|||||||
namespace Zentral.Domain.Entities;
|
namespace Zentral.Domain.Entities;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rappresenta un modulo dell'applicazione (es. Magazzino, Acquisti, Vendite).
|
/// Rappresenta un'applicazione (es. Magazzino, Acquisti, Vendite).
|
||||||
/// I moduli possono essere attivati/disattivati per gestire licenze e funzionalità.
|
/// Le applicazioni possono essere attivate/disattivate per gestire licenze e funzionalità.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class AppModule : BaseEntity
|
public class App : BaseEntity
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Codice univoco del modulo (es. "warehouse", "purchases", "sales")
|
/// Codice univoco dell'applicazione (es. "warehouse", "purchases", "sales")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required string Code { get; set; }
|
public required string Code { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Nome visualizzato del modulo (es. "Magazzino", "Acquisti")
|
/// Nome visualizzato dell'applicazione (es. "Magazzino", "Acquisti")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public required string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Descrizione estesa delle funzionalità del modulo
|
/// Descrizione estesa delle funzionalità dell'applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Description { get; set; }
|
public string? Description { get; set; }
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ public class AppModule : BaseEntity
|
|||||||
public string? Icon { get; set; }
|
public string? Icon { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prezzo base annuale del modulo in EUR
|
/// Prezzo base annuale dell'applicazione in EUR
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public decimal BasePrice { get; set; }
|
public decimal BasePrice { get; set; }
|
||||||
|
|
||||||
@@ -42,30 +42,30 @@ public class AppModule : BaseEntity
|
|||||||
public int SortOrder { get; set; }
|
public int SortOrder { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Se true, il modulo fa parte del core e non può essere disattivato
|
/// Se true, l'applicazione fa parte del core e non può essere disattivata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsCore { get; set; }
|
public bool IsCore { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lista di codici modulo prerequisiti separati da virgola (es. "warehouse,purchases")
|
/// Lista di codici applicazione prerequisiti separati da virgola (es. "warehouse,purchases")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Dependencies { get; set; }
|
public string? Dependencies { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Path base per le route frontend del modulo (es. "/warehouse")
|
/// Path base per le route frontend dell'applicazione (es. "/warehouse")
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? RoutePath { get; set; }
|
public string? RoutePath { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Se false, il modulo è nascosto e non disponibile per l'acquisto
|
/// Se false, l'applicazione è nascosta e non disponibile per l'acquisto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsAvailable { get; set; } = true;
|
public bool IsAvailable { get; set; } = true;
|
||||||
|
|
||||||
// Navigation property
|
// Navigation property
|
||||||
public ModuleSubscription? Subscription { get; set; }
|
public AppSubscription? Subscription { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Restituisce la lista dei codici modulo prerequisiti
|
/// Restituisce la lista dei codici applicazione prerequisiti
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IEnumerable<string> GetDependencies()
|
public IEnumerable<string> GetDependencies()
|
||||||
{
|
{
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
namespace Zentral.Domain.Entities;
|
namespace Zentral.Domain.Entities;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tipo di abbonamento per un modulo
|
/// Tipo di abbonamento per un'applicazione
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum SubscriptionType
|
public enum SubscriptionType
|
||||||
{
|
{
|
||||||
@@ -14,18 +14,18 @@ public enum SubscriptionType
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Rappresenta lo stato di abbonamento/attivazione di un modulo per questa istanza dell'applicazione.
|
/// Rappresenta lo stato di abbonamento/attivazione di un'applicazione.
|
||||||
/// Ogni ModuleSubscription è collegata 1:1 con un AppModule.
|
/// Ogni AppSubscription è collegata 1:1 con un'App.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ModuleSubscription : BaseEntity
|
public class AppSubscription : BaseEntity
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// ID del modulo associato
|
/// ID dell'applicazione associata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int ModuleId { get; set; }
|
public int AppId { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Se true, il modulo è attualmente attivo e accessibile
|
/// Se true, l'applicazione è attualmente attiva e accessibile
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ public class ModuleSubscription : BaseEntity
|
|||||||
public decimal? PaidPrice { get; set; }
|
public decimal? PaidPrice { get; set; }
|
||||||
|
|
||||||
// Navigation property
|
// Navigation property
|
||||||
public AppModule Module { get; set; } = null!;
|
public App App { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Verifica se l'abbonamento è attualmente valido (attivo e non scaduto)
|
/// Verifica se l'abbonamento è attualmente valido (attivo e non scaduto)
|
||||||
@@ -42,9 +42,9 @@ public class ZentralDbContext : DbContext
|
|||||||
public DbSet<ReportImage> ReportImages => Set<ReportImage>();
|
public DbSet<ReportImage> ReportImages => Set<ReportImage>();
|
||||||
public DbSet<VirtualDataset> VirtualDatasets => Set<VirtualDataset>();
|
public DbSet<VirtualDataset> VirtualDatasets => Set<VirtualDataset>();
|
||||||
|
|
||||||
// Module system entities
|
// App system entities
|
||||||
public DbSet<AppModule> AppModules => Set<AppModule>();
|
public DbSet<App> Apps => Set<App>();
|
||||||
public DbSet<ModuleSubscription> ModuleSubscriptions => Set<ModuleSubscription>();
|
public DbSet<AppSubscription> AppSubscriptions => Set<AppSubscription>();
|
||||||
|
|
||||||
// Auto Code system
|
// Auto Code system
|
||||||
public DbSet<AutoCode> AutoCodes => Set<AutoCode>();
|
public DbSet<AutoCode> AutoCodes => Set<AutoCode>();
|
||||||
@@ -348,8 +348,8 @@ public class ZentralDbContext : DbContext
|
|||||||
entity.HasIndex(e => e.Categoria);
|
entity.HasIndex(e => e.Categoria);
|
||||||
});
|
});
|
||||||
|
|
||||||
// AppModule
|
// App
|
||||||
modelBuilder.Entity<AppModule>(entity =>
|
modelBuilder.Entity<App>(entity =>
|
||||||
{
|
{
|
||||||
entity.HasIndex(e => e.Code).IsUnique();
|
entity.HasIndex(e => e.Code).IsUnique();
|
||||||
entity.HasIndex(e => e.SortOrder);
|
entity.HasIndex(e => e.SortOrder);
|
||||||
@@ -361,17 +361,17 @@ public class ZentralDbContext : DbContext
|
|||||||
.HasPrecision(5, 2);
|
.HasPrecision(5, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ModuleSubscription
|
// AppSubscription
|
||||||
modelBuilder.Entity<ModuleSubscription>(entity =>
|
modelBuilder.Entity<AppSubscription>(entity =>
|
||||||
{
|
{
|
||||||
entity.HasIndex(e => e.ModuleId).IsUnique();
|
entity.HasIndex(e => e.AppId).IsUnique();
|
||||||
|
|
||||||
entity.Property(e => e.PaidPrice)
|
entity.Property(e => e.PaidPrice)
|
||||||
.HasPrecision(18, 2);
|
.HasPrecision(18, 2);
|
||||||
|
|
||||||
entity.HasOne(e => e.Module)
|
entity.HasOne(e => e.App)
|
||||||
.WithOne(m => m.Subscription)
|
.WithOne(m => m.Subscription)
|
||||||
.HasForeignKey<ModuleSubscription>(e => e.ModuleId)
|
.HasForeignKey<AppSubscription>(e => e.AppId)
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
4704
src/backend/Zentral.Infrastructure/Migrations/20251205184549_RenameModulesToApps.Designer.cs
generated
Normal file
4704
src/backend/Zentral.Infrastructure/Migrations/20251205184549_RenameModulesToApps.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,185 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Zentral.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class RenameModulesToApps : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ModuleSubscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AppModules");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Apps",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Code = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
Description = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Icon = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
BasePrice = table.Column<decimal>(type: "TEXT", precision: 18, scale: 2, nullable: false),
|
||||||
|
MonthlyMultiplier = table.Column<decimal>(type: "TEXT", precision: 5, scale: 2, nullable: false),
|
||||||
|
SortOrder = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
IsCore = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
Dependencies = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
RoutePath = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
IsAvailable = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
CreatedBy = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedBy = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
CustomFieldsJson = table.Column<string>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Apps", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AppSubscriptions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
AppId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
SubscriptionType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
StartDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
EndDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
AutoRenew = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
Notes = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
LastRenewalDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
PaidPrice = table.Column<decimal>(type: "TEXT", precision: 18, scale: 2, nullable: true),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
CreatedBy = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedBy = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
CustomFieldsJson = table.Column<string>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AppSubscriptions", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_AppSubscriptions_Apps_AppId",
|
||||||
|
column: x => x.AppId,
|
||||||
|
principalTable: "Apps",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Apps_Code",
|
||||||
|
table: "Apps",
|
||||||
|
column: "Code",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Apps_SortOrder",
|
||||||
|
table: "Apps",
|
||||||
|
column: "SortOrder");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AppSubscriptions_AppId",
|
||||||
|
table: "AppSubscriptions",
|
||||||
|
column: "AppId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "AppSubscriptions");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Apps");
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "AppModules",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
BasePrice = table.Column<decimal>(type: "TEXT", precision: 18, scale: 2, nullable: false),
|
||||||
|
Code = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
CreatedBy = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
CustomFieldsJson = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Dependencies = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Description = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
Icon = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
IsAvailable = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
IsCore = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
MonthlyMultiplier = table.Column<decimal>(type: "TEXT", precision: 5, scale: 2, nullable: false),
|
||||||
|
Name = table.Column<string>(type: "TEXT", nullable: false),
|
||||||
|
RoutePath = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
SortOrder = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedBy = table.Column<string>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_AppModules", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ModuleSubscriptions",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "INTEGER", nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
ModuleId = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
AutoRenew = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
CreatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
CreatedBy = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
CustomFieldsJson = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
EndDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
IsEnabled = table.Column<bool>(type: "INTEGER", nullable: false),
|
||||||
|
LastRenewalDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
Notes = table.Column<string>(type: "TEXT", nullable: true),
|
||||||
|
PaidPrice = table.Column<decimal>(type: "TEXT", precision: 18, scale: 2, nullable: true),
|
||||||
|
StartDate = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
SubscriptionType = table.Column<int>(type: "INTEGER", nullable: false),
|
||||||
|
UpdatedAt = table.Column<DateTime>(type: "TEXT", nullable: true),
|
||||||
|
UpdatedBy = table.Column<string>(type: "TEXT", nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ModuleSubscriptions", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ModuleSubscriptions_AppModules_ModuleId",
|
||||||
|
column: x => x.ModuleId,
|
||||||
|
principalTable: "AppModules",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AppModules_Code",
|
||||||
|
table: "AppModules",
|
||||||
|
column: "Code",
|
||||||
|
unique: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_AppModules_SortOrder",
|
||||||
|
table: "AppModules",
|
||||||
|
column: "SortOrder");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ModuleSubscriptions_ModuleId",
|
||||||
|
table: "ModuleSubscriptions",
|
||||||
|
column: "ModuleId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ namespace Zentral.Infrastructure.Migrations
|
|||||||
#pragma warning disable 612, 618
|
#pragma warning disable 612, 618
|
||||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.0");
|
modelBuilder.HasAnnotation("ProductVersion", "9.0.0");
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.AppModule", b =>
|
modelBuilder.Entity("Zentral.Domain.Entities.App", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
@@ -82,7 +82,64 @@ namespace Zentral.Infrastructure.Migrations
|
|||||||
|
|
||||||
b.HasIndex("SortOrder");
|
b.HasIndex("SortOrder");
|
||||||
|
|
||||||
b.ToTable("AppModules");
|
b.ToTable("Apps");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Zentral.Domain.Entities.AppSubscription", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<int>("AppId")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<bool>("AutoRenew")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("CreatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CreatedBy")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("CustomFieldsJson")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("EndDate")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEnabled")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastRenewalDate")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("Notes")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<decimal?>("PaidPrice")
|
||||||
|
.HasPrecision(18, 2)
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("StartDate")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<int>("SubscriptionType")
|
||||||
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("UpdatedAt")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.Property<string>("UpdatedBy")
|
||||||
|
.HasColumnType("TEXT");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AppId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("AppSubscriptions");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.Articolo", b =>
|
modelBuilder.Entity("Zentral.Domain.Entities.Articolo", b =>
|
||||||
@@ -1250,63 +1307,6 @@ namespace Zentral.Infrastructure.Migrations
|
|||||||
b.ToTable("Location");
|
b.ToTable("Location");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.ModuleSubscription", b =>
|
|
||||||
{
|
|
||||||
b.Property<int>("Id")
|
|
||||||
.ValueGeneratedOnAdd()
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<bool>("AutoRenew")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("CreatedAt")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("CreatedBy")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("CustomFieldsJson")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("EndDate")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<bool>("IsEnabled")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("LastRenewalDate")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("ModuleId")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<string>("Notes")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<decimal?>("PaidPrice")
|
|
||||||
.HasPrecision(18, 2)
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("StartDate")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("SubscriptionType")
|
|
||||||
.HasColumnType("INTEGER");
|
|
||||||
|
|
||||||
b.Property<DateTime?>("UpdatedAt")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<string>("UpdatedBy")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.HasKey("Id");
|
|
||||||
|
|
||||||
b.HasIndex("ModuleId")
|
|
||||||
.IsUnique();
|
|
||||||
|
|
||||||
b.ToTable("ModuleSubscriptions");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.Production.BillOfMaterials", b =>
|
modelBuilder.Entity("Zentral.Domain.Entities.Production.BillOfMaterials", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -3839,6 +3839,17 @@ namespace Zentral.Infrastructure.Migrations
|
|||||||
b.ToTable("WarehouseLocations", (string)null);
|
b.ToTable("WarehouseLocations", (string)null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Zentral.Domain.Entities.AppSubscription", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Zentral.Domain.Entities.App", "App")
|
||||||
|
.WithOne("Subscription")
|
||||||
|
.HasForeignKey("Zentral.Domain.Entities.AppSubscription", "AppId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("App");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.Articolo", b =>
|
modelBuilder.Entity("Zentral.Domain.Entities.Articolo", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Zentral.Domain.Entities.CodiceCategoria", "Categoria")
|
b.HasOne("Zentral.Domain.Entities.CodiceCategoria", "Categoria")
|
||||||
@@ -4025,17 +4036,6 @@ namespace Zentral.Infrastructure.Migrations
|
|||||||
b.Navigation("Dipendente");
|
b.Navigation("Dipendente");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.ModuleSubscription", b =>
|
|
||||||
{
|
|
||||||
b.HasOne("Zentral.Domain.Entities.AppModule", "Module")
|
|
||||||
.WithOne("Subscription")
|
|
||||||
.HasForeignKey("Zentral.Domain.Entities.ModuleSubscription", "ModuleId")
|
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
|
||||||
.IsRequired();
|
|
||||||
|
|
||||||
b.Navigation("Module");
|
|
||||||
});
|
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.Production.BillOfMaterials", b =>
|
modelBuilder.Entity("Zentral.Domain.Entities.Production.BillOfMaterials", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Zentral.Domain.Entities.Warehouse.WarehouseArticle", "Article")
|
b.HasOne("Zentral.Domain.Entities.Warehouse.WarehouseArticle", "Article")
|
||||||
@@ -4519,7 +4519,7 @@ namespace Zentral.Infrastructure.Migrations
|
|||||||
b.Navigation("ParentCategory");
|
b.Navigation("ParentCategory");
|
||||||
});
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Zentral.Domain.Entities.AppModule", b =>
|
modelBuilder.Entity("Zentral.Domain.Entities.App", b =>
|
||||||
{
|
{
|
||||||
b.Navigation("Subscription");
|
b.Navigation("Subscription");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"production": "Production",
|
"production": "Production",
|
||||||
"hr": "Human Resources",
|
"hr": "Human Resources",
|
||||||
"reports": "Reports",
|
"reports": "Reports",
|
||||||
"modules": "Modules",
|
"apps": "Apps",
|
||||||
"autoCodes": "Auto Codes",
|
"autoCodes": "Auto Codes",
|
||||||
"customFields": "Custom Fields"
|
"customFields": "Custom Fields"
|
||||||
},
|
},
|
||||||
@@ -257,7 +257,7 @@
|
|||||||
"preventivo": "Quote",
|
"preventivo": "Quote",
|
||||||
"confermato": "Confirmed"
|
"confermato": "Confirmed"
|
||||||
},
|
},
|
||||||
"modules": {
|
"apps": {
|
||||||
"warehouse": {
|
"warehouse": {
|
||||||
"title": "Warehouse Management",
|
"title": "Warehouse Management",
|
||||||
"inventory": "Inventory",
|
"inventory": "Inventory",
|
||||||
@@ -274,13 +274,13 @@
|
|||||||
"rimborsi": "Reimbursements"
|
"rimborsi": "Reimbursements"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Module Management",
|
"title": "App Management",
|
||||||
"subtitle": "Configure active modules and manage subscriptions",
|
"subtitle": "Configure active apps and manage subscriptions",
|
||||||
"checkExpired": "Check Expired",
|
"checkExpired": "Check Expired",
|
||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
"expiringWarning": "{{count}} module(s) expiring in the next 30 days:",
|
"expiringWarning": "{{count}} app(s) expiring in the next 30 days:",
|
||||||
"disableConfirmTitle": "Confirm Deactivation",
|
"disableConfirmTitle": "Confirm Deactivation",
|
||||||
"disableConfirmText": "Are you sure you want to deactivate the module",
|
"disableConfirmText": "Are you sure you want to deactivate the app",
|
||||||
"disableConfirmSubtext": "Entered data will remain in the system but will not be accessible until reactivation.",
|
"disableConfirmSubtext": "Entered data will remain in the system but will not be accessible until reactivation.",
|
||||||
"disable": "Deactivate",
|
"disable": "Deactivate",
|
||||||
"enable": "Activate",
|
"enable": "Activate",
|
||||||
@@ -300,9 +300,9 @@
|
|||||||
"autoRenew": "Auto Renew",
|
"autoRenew": "Auto Renew",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"purchaseTitle": "Activate Module",
|
"purchaseTitle": "Activate App",
|
||||||
"purchaseSubtitle": "Choose the subscription plan for the module {{name}}",
|
"purchaseSubtitle": "Choose the subscription plan for the app {{name}}",
|
||||||
"missingDependencies": "This module requires the following modules which are not active:",
|
"missingDependencies": "This app requires the following apps which are not active:",
|
||||||
"subscriptionType": "Subscription Type",
|
"subscriptionType": "Subscription Type",
|
||||||
"monthly": "Monthly",
|
"monthly": "Monthly",
|
||||||
"annual": "Annual",
|
"annual": "Annual",
|
||||||
@@ -313,16 +313,16 @@
|
|||||||
"orderSummary": "Order Summary",
|
"orderSummary": "Order Summary",
|
||||||
"total": "Total",
|
"total": "Total",
|
||||||
"activating": "Activating...",
|
"activating": "Activating...",
|
||||||
"activateModule": "Activate Module",
|
"activateModule": "Activate App",
|
||||||
"purchaseNote": "You can deactivate the module at any time from the settings. Entered data will remain available.",
|
"purchaseNote": "You can deactivate the app at any time from the settings. Entered data will remain available.",
|
||||||
"includedFeatures": "Included Features",
|
"includedFeatures": "Included Features",
|
||||||
"moduleNotFound": "Module Not Found",
|
"moduleNotFound": "App Not Found",
|
||||||
"moduleNotFoundText": "The requested module does not exist.",
|
"moduleNotFoundText": "The requested app does not exist.",
|
||||||
"backToHome": "Back to Home",
|
"backToHome": "Back to Home",
|
||||||
"status": "Status",
|
"status": "Status",
|
||||||
"module": "Module",
|
"module": "App",
|
||||||
"subscription": "Subscription",
|
"subscription": "Subscription",
|
||||||
"activationError": "Error during module activation"
|
"activationError": "Error during app activation"
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"warehouse": {
|
"warehouse": {
|
||||||
@@ -373,7 +373,7 @@
|
|||||||
"4": "Expense reports and reimbursements",
|
"4": "Expense reports and reimbursements",
|
||||||
"5": "Personnel cost analysis"
|
"5": "Personnel cost analysis"
|
||||||
},
|
},
|
||||||
"default": "Complete module features"
|
"default": "Complete app features"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoCodes": {
|
"autoCodes": {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
"production": "Produzione",
|
"production": "Produzione",
|
||||||
"hr": "Gestione Personale",
|
"hr": "Gestione Personale",
|
||||||
"reports": "Report",
|
"reports": "Report",
|
||||||
"modules": "Moduli",
|
"apps": "Applicazioni",
|
||||||
"autoCodes": "Codici Auto",
|
"autoCodes": "Codici Auto",
|
||||||
"customFields": "Campi Personalizzati"
|
"customFields": "Campi Personalizzati"
|
||||||
},
|
},
|
||||||
@@ -253,7 +253,7 @@
|
|||||||
"preventivo": "Preventivo",
|
"preventivo": "Preventivo",
|
||||||
"confermato": "Confermato"
|
"confermato": "Confermato"
|
||||||
},
|
},
|
||||||
"modules": {
|
"apps": {
|
||||||
"warehouse": {
|
"warehouse": {
|
||||||
"title": "Gestione Magazzino",
|
"title": "Gestione Magazzino",
|
||||||
"inventory": "Inventario",
|
"inventory": "Inventario",
|
||||||
@@ -270,13 +270,13 @@
|
|||||||
"rimborsi": "Rimborsi"
|
"rimborsi": "Rimborsi"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Gestione Moduli",
|
"title": "Gestione Applicazioni",
|
||||||
"subtitle": "Configura i moduli attivi e gestisci le subscription",
|
"subtitle": "Configura le applicazioni attive e gestisci le subscription",
|
||||||
"checkExpired": "Controlla Scadenze",
|
"checkExpired": "Controlla Scadenze",
|
||||||
"refresh": "Aggiorna",
|
"refresh": "Aggiorna",
|
||||||
"expiringWarning": "{{count}} modulo/i in scadenza nei prossimi 30 giorni:",
|
"expiringWarning": "{{count}} applicazione/i in scadenza nei prossimi 30 giorni:",
|
||||||
"disableConfirmTitle": "Conferma disattivazione",
|
"disableConfirmTitle": "Conferma disattivazione",
|
||||||
"disableConfirmText": "Sei sicuro di voler disattivare il modulo",
|
"disableConfirmText": "Sei sicuro di voler disattivare l'applicazione",
|
||||||
"disableConfirmSubtext": "I dati inseriti rimarranno nel sistema ma non saranno più accessibili fino alla riattivazione.",
|
"disableConfirmSubtext": "I dati inseriti rimarranno nel sistema ma non saranno più accessibili fino alla riattivazione.",
|
||||||
"disable": "Disattiva",
|
"disable": "Disattiva",
|
||||||
"enable": "Attiva",
|
"enable": "Attiva",
|
||||||
@@ -297,9 +297,9 @@
|
|||||||
"autoRenew": "Rinnova automatico",
|
"autoRenew": "Rinnova automatico",
|
||||||
"yes": "Sì",
|
"yes": "Sì",
|
||||||
"no": "No",
|
"no": "No",
|
||||||
"purchaseTitle": "Attiva Modulo",
|
"purchaseTitle": "Attiva Applicazione",
|
||||||
"purchaseSubtitle": "Scegli il piano di abbonamento per il modulo {{name}}",
|
"purchaseSubtitle": "Scegli il piano di abbonamento per l'applicazione {{name}}",
|
||||||
"missingDependencies": "Questo modulo richiede i seguenti moduli che non sono attivi:",
|
"missingDependencies": "Questa applicazione richiede le seguenti applicazioni che non sono attive:",
|
||||||
"subscriptionType": "Tipo di abbonamento",
|
"subscriptionType": "Tipo di abbonamento",
|
||||||
"monthly": "Mensile",
|
"monthly": "Mensile",
|
||||||
"annual": "Annuale",
|
"annual": "Annuale",
|
||||||
@@ -310,16 +310,16 @@
|
|||||||
"orderSummary": "Riepilogo ordine",
|
"orderSummary": "Riepilogo ordine",
|
||||||
"total": "Totale",
|
"total": "Totale",
|
||||||
"activating": "Attivazione in corso...",
|
"activating": "Attivazione in corso...",
|
||||||
"activateModule": "Attiva Modulo",
|
"activateModule": "Attiva Applicazione",
|
||||||
"purchaseNote": "Potrai disattivare il modulo in qualsiasi momento dalle impostazioni. I dati inseriti rimarranno disponibili.",
|
"purchaseNote": "Potrai disattivare l'applicazione in qualsiasi momento dalle impostazioni. I dati inseriti rimarranno disponibili.",
|
||||||
"includedFeatures": "Funzionalità incluse",
|
"includedFeatures": "Funzionalità incluse",
|
||||||
"moduleNotFound": "Modulo non trovato",
|
"moduleNotFound": "Applicazione non trovata",
|
||||||
"moduleNotFoundText": "Il modulo richiesto non esiste.",
|
"moduleNotFoundText": "L'applicazione richiesta non esiste.",
|
||||||
"backToHome": "Torna alla Home",
|
"backToHome": "Torna alla Home",
|
||||||
"status": "Stato",
|
"status": "Stato",
|
||||||
"module": "Modulo",
|
"module": "Applicazione",
|
||||||
"subscription": "Abbonamento",
|
"subscription": "Abbonamento",
|
||||||
"activationError": "Errore durante l'attivazione del modulo"
|
"activationError": "Errore durante l'attivazione dell'applicazione"
|
||||||
},
|
},
|
||||||
"features": {
|
"features": {
|
||||||
"warehouse": {
|
"warehouse": {
|
||||||
@@ -370,7 +370,7 @@
|
|||||||
"4": "Note spese e rimborsi",
|
"4": "Note spese e rimborsi",
|
||||||
"5": "Analisi costi personale"
|
"5": "Analisi costi personale"
|
||||||
},
|
},
|
||||||
"default": "Funzionalità complete del modulo"
|
"default": "Funzionalità complete dell'applicazione"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"autoCodes": {
|
"autoCodes": {
|
||||||
|
|||||||
@@ -8,21 +8,21 @@ import { AppLanguageProvider } from "./contexts/LanguageContext";
|
|||||||
import Layout from "./components/Layout";
|
import Layout from "./components/Layout";
|
||||||
import Dashboard from "./pages/Dashboard";
|
import Dashboard from "./pages/Dashboard";
|
||||||
|
|
||||||
import ReportDesignerRoutes from "./modules/report-designer/routes";
|
import ReportDesignerRoutes from "./apps/report-designer/routes";
|
||||||
import ModulesAdminPage from "./pages/ModulesAdminPage";
|
import AppsAdminPage from "./pages/AppsAdminPage";
|
||||||
import ModulePurchasePage from "./pages/ModulePurchasePage";
|
import ModulePurchasePage from "./pages/AppPurchasePage";
|
||||||
import AutoCodesAdminPage from "./pages/AutoCodesAdminPage";
|
import AutoCodesAdminPage from "./pages/AutoCodesAdminPage";
|
||||||
import CustomFieldsAdminPage from "./pages/CustomFieldsAdminPage";
|
import CustomFieldsAdminPage from "./pages/CustomFieldsAdminPage";
|
||||||
import WarehouseRoutes from "./modules/warehouse/routes";
|
import WarehouseRoutes from "./apps/warehouse/routes";
|
||||||
import PurchasesRoutes from "./modules/purchases/routes";
|
import PurchasesRoutes from "./apps/purchases/routes";
|
||||||
import SalesRoutes from "./modules/sales/routes";
|
import SalesRoutes from "./apps/sales/routes";
|
||||||
import ProductionRoutes from "./modules/production/routes";
|
import ProductionRoutes from "./apps/production/routes";
|
||||||
import EventsRoutes from "./modules/events/routes";
|
import EventsRoutes from "./apps/events/routes";
|
||||||
import HRRoutes from "./modules/hr/routes";
|
import HRRoutes from "./apps/hr/routes";
|
||||||
import { ModuleGuard } from "./components/ModuleGuard";
|
import { AppGuard } from "./components/AppGuard";
|
||||||
import { useRealTimeUpdates } from "./hooks/useRealTimeUpdates";
|
import { useRealTimeUpdates } from "./hooks/useRealTimeUpdates";
|
||||||
import { CollaborationProvider } from "./contexts/CollaborationContext";
|
import { CollaborationProvider } from "./contexts/CollaborationContext";
|
||||||
import { ModuleProvider } from "./contexts/ModuleContext";
|
import { AppProvider } from "./contexts/AppContext";
|
||||||
import { TabProvider } from "./contexts/TabContext";
|
import { TabProvider } from "./contexts/TabContext";
|
||||||
|
|
||||||
const queryClient = new QueryClient({
|
const queryClient = new QueryClient({
|
||||||
@@ -50,7 +50,7 @@ function App() {
|
|||||||
<AppLanguageProvider>
|
<AppLanguageProvider>
|
||||||
<AppThemeProvider>
|
<AppThemeProvider>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<ModuleProvider>
|
<AppProvider>
|
||||||
<CollaborationProvider>
|
<CollaborationProvider>
|
||||||
<RealTimeProvider>
|
<RealTimeProvider>
|
||||||
<TabProvider>
|
<TabProvider>
|
||||||
@@ -62,15 +62,15 @@ function App() {
|
|||||||
<Route
|
<Route
|
||||||
path="report-designer/*"
|
path="report-designer/*"
|
||||||
element={
|
element={
|
||||||
<ModuleGuard moduleCode="report-designer">
|
<AppGuard appCode="report-designer">
|
||||||
<ReportDesignerRoutes />
|
<ReportDesignerRoutes />
|
||||||
</ModuleGuard>
|
</AppGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* Admin */}
|
{/* Admin */}
|
||||||
<Route path="modules" element={<ModulesAdminPage />} />
|
<Route path="apps" element={<AppsAdminPage />} />
|
||||||
<Route
|
<Route
|
||||||
path="modules/purchase/:code"
|
path="apps/purchase/:code"
|
||||||
element={<ModulePurchasePage />}
|
element={<ModulePurchasePage />}
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
@@ -85,54 +85,54 @@ function App() {
|
|||||||
<Route
|
<Route
|
||||||
path="warehouse/*"
|
path="warehouse/*"
|
||||||
element={
|
element={
|
||||||
<ModuleGuard moduleCode="warehouse">
|
<AppGuard appCode="warehouse">
|
||||||
<WarehouseRoutes />
|
<WarehouseRoutes />
|
||||||
</ModuleGuard>
|
</AppGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* Purchases Module */}
|
{/* Purchases Module */}
|
||||||
<Route
|
<Route
|
||||||
path="purchases/*"
|
path="purchases/*"
|
||||||
element={
|
element={
|
||||||
<ModuleGuard moduleCode="purchases">
|
<AppGuard appCode="purchases">
|
||||||
<PurchasesRoutes />
|
<PurchasesRoutes />
|
||||||
</ModuleGuard>
|
</AppGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* Sales Module */}
|
{/* Sales Module */}
|
||||||
<Route
|
<Route
|
||||||
path="sales/*"
|
path="sales/*"
|
||||||
element={
|
element={
|
||||||
<ModuleGuard moduleCode="sales">
|
<AppGuard appCode="sales">
|
||||||
<SalesRoutes />
|
<SalesRoutes />
|
||||||
</ModuleGuard>
|
</AppGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* Production Module */}
|
{/* Production Module */}
|
||||||
<Route
|
<Route
|
||||||
path="production/*"
|
path="production/*"
|
||||||
element={
|
element={
|
||||||
<ModuleGuard moduleCode="production">
|
<AppGuard appCode="production">
|
||||||
<ProductionRoutes />
|
<ProductionRoutes />
|
||||||
</ModuleGuard>
|
</AppGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* Events Module */}
|
{/* Events Module */}
|
||||||
<Route
|
<Route
|
||||||
path="events/*"
|
path="events/*"
|
||||||
element={
|
element={
|
||||||
<ModuleGuard moduleCode="events">
|
<AppGuard appCode="events">
|
||||||
<EventsRoutes />
|
<EventsRoutes />
|
||||||
</ModuleGuard>
|
</AppGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
{/* HR Module */}
|
{/* HR Module */}
|
||||||
<Route
|
<Route
|
||||||
path="hr/*"
|
path="hr/*"
|
||||||
element={
|
element={
|
||||||
<ModuleGuard moduleCode="hr">
|
<AppGuard appCode="hr">
|
||||||
<HRRoutes />
|
<HRRoutes />
|
||||||
</ModuleGuard>
|
</AppGuard>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Route>
|
</Route>
|
||||||
@@ -140,7 +140,7 @@ function App() {
|
|||||||
</TabProvider>
|
</TabProvider>
|
||||||
</RealTimeProvider>
|
</RealTimeProvider>
|
||||||
</CollaborationProvider>
|
</CollaborationProvider>
|
||||||
</ModuleProvider>
|
</AppProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</AppThemeProvider>
|
</AppThemeProvider>
|
||||||
</AppLanguageProvider>
|
</AppLanguageProvider>
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ import {
|
|||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import { useTranslation, Trans } from "react-i18next";
|
import { useTranslation, Trans } from "react-i18next";
|
||||||
import { eventiService } from "../services/eventiService";
|
import { eventiService } from "../../../services/eventiService";
|
||||||
import { demoService, DemoDataResult } from "../services/demoService";
|
import { demoService, DemoDataResult } from "../../../services/demoService";
|
||||||
import { StatoEvento } from "../types";
|
import { StatoEvento, Evento } from "../../../types";
|
||||||
|
|
||||||
const StatCard = ({
|
const StatCard = ({
|
||||||
title,
|
title,
|
||||||
@@ -104,7 +104,7 @@ export default function Dashboard() {
|
|||||||
const [result, setResult] = useState<DemoDataResult | null>(null);
|
const [result, setResult] = useState<DemoDataResult | null>(null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
const { data: eventi = [] } = useQuery({
|
const { data: eventi = [] } = useQuery<Evento[]>({
|
||||||
queryKey: ["eventi"],
|
queryKey: ["eventi"],
|
||||||
queryFn: () => eventiService.getAll(),
|
queryFn: () => eventiService.getAll(),
|
||||||
});
|
});
|
||||||
@@ -152,19 +152,19 @@ export default function Dashboard() {
|
|||||||
|
|
||||||
const eventiProssimi = eventi
|
const eventiProssimi = eventi
|
||||||
.filter(
|
.filter(
|
||||||
(e) =>
|
(e: Evento) =>
|
||||||
dayjs(e.dataEvento).isAfter(oggi) &&
|
dayjs(e.dataEvento).isAfter(oggi) &&
|
||||||
dayjs(e.dataEvento).isBefore(prossimi30Giorni),
|
dayjs(e.dataEvento).isBefore(prossimi30Giorni),
|
||||||
)
|
)
|
||||||
.sort((a, b) => dayjs(a.dataEvento).diff(dayjs(b.dataEvento)));
|
.sort((a: Evento, b: Evento) => dayjs(a.dataEvento).diff(dayjs(b.dataEvento)));
|
||||||
|
|
||||||
const eventiConfermati = eventi.filter(
|
const eventiConfermati = eventi.filter(
|
||||||
(e) => e.stato === StatoEvento.Confermato,
|
(e: Evento) => e.stato === StatoEvento.Confermato,
|
||||||
).length;
|
).length;
|
||||||
const eventiPreventivo = eventi.filter(
|
const eventiPreventivo = eventi.filter(
|
||||||
(e) => e.stato === StatoEvento.Preventivo,
|
(e: Evento) => e.stato === StatoEvento.Preventivo,
|
||||||
).length;
|
).length;
|
||||||
const eventiOggi = eventi.filter((e) =>
|
const eventiOggi = eventi.filter((e: Evento) =>
|
||||||
dayjs(e.dataEvento).isSame(oggi, "day"),
|
dayjs(e.dataEvento).isSame(oggi, "day"),
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
@@ -241,7 +241,7 @@ export default function Dashboard() {
|
|||||||
{t("dashboard.upcomingEvents")}
|
{t("dashboard.upcomingEvents")}
|
||||||
</Typography>
|
</Typography>
|
||||||
<List>
|
<List>
|
||||||
{eventiProssimi.slice(0, 10).map((evento) => (
|
{eventiProssimi.slice(0, 10).map((evento: Evento) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={evento.id}
|
key={evento.id}
|
||||||
component="div"
|
component="div"
|
||||||
@@ -290,7 +290,7 @@ export default function Dashboard() {
|
|||||||
<List>
|
<List>
|
||||||
{eventi
|
{eventi
|
||||||
.filter(
|
.filter(
|
||||||
(e) =>
|
(e: Evento) =>
|
||||||
e.stato === StatoEvento.Preventivo &&
|
e.stato === StatoEvento.Preventivo &&
|
||||||
e.dataScadenzaPreventivo,
|
e.dataScadenzaPreventivo,
|
||||||
)
|
)
|
||||||
@@ -300,7 +300,7 @@ export default function Dashboard() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.slice(0, 5)
|
.slice(0, 5)
|
||||||
.map((evento) => (
|
.map((evento: Evento) => (
|
||||||
<ListItem
|
<ListItem
|
||||||
key={evento.id}
|
key={evento.id}
|
||||||
component="div"
|
component="div"
|
||||||
@@ -321,7 +321,7 @@ export default function Dashboard() {
|
|||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
))}
|
))}
|
||||||
{eventi.filter((e) => e.stato === StatoEvento.Preventivo)
|
{eventi.filter((e: Evento) => e.stato === StatoEvento.Preventivo)
|
||||||
.length === 0 && (
|
.length === 0 && (
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<ListItemText primary={t("dashboard.noQuotes")} />
|
<ListItemText primary={t("dashboard.noQuotes")} />
|
||||||
@@ -64,7 +64,7 @@ export default function DipendentiPage() {
|
|||||||
const [openDialog, setOpenDialog] = useState(false);
|
const [openDialog, setOpenDialog] = useState(false);
|
||||||
const [editingId, setEditingId] = useState<number | null>(null);
|
const [editingId, setEditingId] = useState<number | null>(null);
|
||||||
const [formData, setFormData] = useState<Partial<Dipendente>>({});
|
const [formData, setFormData] = useState<Partial<Dipendente>>({});
|
||||||
const [search, setSearch] = useState('');
|
const [search] = useState('');
|
||||||
|
|
||||||
const { data: dipendenti = [], isLoading } = useQuery({
|
const { data: dipendenti = [], isLoading } = useQuery({
|
||||||
queryKey: ['dipendenti', search],
|
queryKey: ['dipendenti', search],
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user