移除历史状态归一化及相关遗留逻辑

- 移除 LegacyStatusNormalizationMigrator,仅保留 AreaLayoutModeDefaultMigrator
- 删除 WmsDispatchStatus 枚举、常量和全局 using
- 统一所有 DbContext 注入为 MiGuDbContext,移除 PlatformDbContext
- 服务实体操作统一用 IEditableRepository<T>,移除本地实现
- 移除 WmsService 的 MigrateLegacyAsync 方法
- 精简接口模型,移除部分字段和请求体
- 前端保存容器时 status 字段取自已有数据,移除写死默认值
- 更新文档,去除旧说明,统一数据库初始化流程
This commit is contained in:
2026-08-03 09:41:03 +08:00
parent 1f72488a8d
commit 125372b157
26 changed files with 63 additions and 183 deletions
+4 -23
View File
@@ -29,35 +29,16 @@ public sealed class SimpleFieldsCarTypeBackfillMigrator : IDataMigrator
}
}
/// <summary>
/// 把库内旧状态字符串刷成规范枚举名(Available/Idle→EmptyOccupied→FullContainer)。
/// 仅 Sqlite 表名/列名;绕过枚举 HasConversionExecuteUpdate + 字符串比较会 InvalidCast)。
/// </summary>
public sealed class LegacyStatusNormalizationMigrator : IDataMigrator
/// <summary>库区 LayoutMode 空值补 Flatraw UPDATE,避开枚举 converter)。</summary>
public sealed class AreaLayoutModeDefaultMigrator : IDataMigrator
{
public int Order => 15;
public string Name => "Wms.LegacyStatusNormalization";
public string Name => "Wms.AreaLayoutModeDefault";
public async Task MigrateAsync(DbContext db, CancellationToken ct = default)
{
if (db is not MiGuDbContext) return;
await db.Database.ExecuteSqlRawAsync(
"""
UPDATE wms_storages
SET Status = 'Empty'
WHERE Status IN ('Available', 'Idle')
""",
ct);
await db.Database.ExecuteSqlRawAsync(
"""
UPDATE wms_storages
SET Status = 'FullContainer'
WHERE Status = 'Occupied'
""",
ct);
await db.Database.ExecuteSqlRawAsync(
"""
UPDATE wms_areas
@@ -98,7 +79,7 @@ public static class DataMigratorRegistration
public static IServiceCollection AddMiGuDataMigrators(this IServiceCollection services)
{
services.AddSingleton<IDataMigrator, SimpleFieldsCarTypeBackfillMigrator>();
services.AddSingleton<IDataMigrator, LegacyStatusNormalizationMigrator>();
services.AddSingleton<IDataMigrator, AreaLayoutModeDefaultMigrator>();
services.AddSingleton<IDataMigrator, ContainerLocationStorageIdBackfillMigrator>();
return services;
}
@@ -96,9 +96,3 @@ public static class WmsReservationStatuses
public const WmsReservationStatus Released = WmsReservationStatus.Released;
public const WmsReservationStatus Expired = WmsReservationStatus.Expired;
}
public static class WmsDispatchStatuses
{
public const WmsDispatchStatus Dispatched = WmsDispatchStatus.Dispatched;
public const WmsDispatchStatus Failed = WmsDispatchStatus.Failed;
}
@@ -27,9 +27,3 @@ public enum WmsReservationStatus
Released,
Expired
}
public enum WmsDispatchStatus
{
Dispatched,
Failed
}
-1
View File
@@ -2,7 +2,6 @@ namespace MiGu.DB.Domains.Wms;
/// <summary>
/// WMS 状态/类型枚举。列以字符串存储(见约定 HasConversion&lt;string&gt;),成员名即库内合法值。
/// 旧别名(Available/Idle/Occupied 等)不进入枚举,由 LegacyStatusNormalizationMigrator 刷库。
/// </summary>
public enum AreaLayoutMode
{
+2 -11
View File
@@ -33,17 +33,8 @@ public static class StorageStatuses
public static readonly HashSet<StorageStatus> All = new()
{ Empty, EmptyContainer, FullContainer, Disabled };
/// <summary>
/// 写路径归一:兼容历史字符串 Available/Idle/Occupied。
/// 库内残留旧值须靠 DataMigrator 刷掉,不能依赖 converter 读侧归一(WHERE 会漏行)。
/// </summary>
public static StorageStatus Normalize(string? status) => status switch
{
"Available" or "Idle" => Empty,
"Occupied" => FullContainer,
_ when Enum.TryParse<StorageStatus>(status, true, out var e) && All.Contains(e) => e,
_ => Empty
};
public static StorageStatus ParseOr(string? value, StorageStatus fallback = StorageStatus.Empty) =>
Enum.TryParse<StorageStatus>(value, true, out var e) && All.Contains(e) ? e : fallback;
}
public static class ContainerStatuses
+3 -3
View File
@@ -94,7 +94,7 @@ dotnet ef migrations add <迁移名称> `
### 3.4 应用到本地库
启动 `MiGu.Server` 即可(`EnsurePlatformDatabaseAsync` `MigrateMiGuDbAsync`),或:
启动 `MiGu.Server` 即可(`Program.cs` 直接调用 `MigrateMiGuDbAsync`),或:
```powershell
dotnet ef database update `
@@ -151,7 +151,7 @@ dotnet ef database update <目标迁移名> `
**[MiGu.Server/README.md · 数据库启动流程](../MiGu.Server/README.md#数据库启动流程)**
摘要:`EnsurePlatformDatabaseAsync``MigrateMiGuDbAsync``Database:SchemaMode``EnsureCreated``Migrate`;之后按需跑 `IDataMigrator`
摘要:`MigrateMiGuDbAsync``Database:SchemaMode``EnsureCreated``Migrate`;之后按需跑 `IDataMigrator`
**Migrate 基线:** 已有表、无 History 时,会把**全部** pending Migration 写入 `__EFMigrationsHistory`(假定 EnsureCreated 库已对齐模型 tip)。发版前若开发期改过模型,须先 `migrations add` 再切 `Migrate`
@@ -165,7 +165,7 @@ dotnet ef database update <目标迁移名> `
| 刷旧枚举字符串、回填列 | 新增 `IDataMigrator`,注册到 `AddMiGuDataMigrators` |
| 开发机整库清空重来 | 删 `data/platform.db*` 后启动(等同空库 Migrate);**不要**在生产用 EnsureDeleted |
注意:带 `HasConversion` 的枚举列,用 `ExecuteUpdate` + 原始字符串比较可能触发转换异常;旧值刷库需绕过 converter(参见 `LegacyStatusNormalizationMigrator`)。
注意:带 `HasConversion` 的枚举列,用 `ExecuteUpdate` + 原始字符串比较可能触发转换异常;空 LayoutMode 等特例用 raw UPDATE(参见 `AreaLayoutModeDefaultMigrator`)。
---
+1 -2
View File
@@ -17,7 +17,7 @@
```csharp
builder.Services.AddPlatformPersistence(builder.Configuration); // 内部 AddMiGuDb
await app.Services.EnsurePlatformDatabaseAsync(); // 内部 MigrateMiGuDbAsync
await app.Services.MigrateMiGuDbAsync();
```
**启动流程、SchemaMode、开发/发版配置说明见 [MiGu.Server/README.md · 数据库启动流程](../MiGu.Server/README.md#数据库启动流程)。**
@@ -27,7 +27,6 @@ await app.Services.EnsurePlatformDatabaseAsync(); // 内部 Migrat
## 实体与枚举
- 业务状态字段为 **enum**,约定自动 `HasConversion<string>()`(严格 1:1,不做读侧归一)。
- 旧库值(如 `Available`/`Idle`)由 `LegacyStatusNormalizationMigrator` 一次性刷成规范名。
- `Version` 为乐观并发令牌;软删走全局 `HasQueryFilter`
- 复数辅助类(`StorageStatuses``LocationKinds`…)负责 API 字符串解析与集合校验。
+2 -2
View File
@@ -15,9 +15,9 @@ public sealed class FleetController : ControllerBase
private readonly FleetHealthService _health;
private readonly CdmTaskSyncer _cdmSyncer;
private readonly AlarmCollector _alarmCollector;
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
public FleetController(FleetHealthService health, CdmTaskSyncer cdmSyncer, AlarmCollector alarmCollector, PlatformDbContext db)
public FleetController(FleetHealthService health, CdmTaskSyncer cdmSyncer, AlarmCollector alarmCollector, MiGuDbContext db)
{
_health = health;
_cdmSyncer = cdmSyncer;
-4
View File
@@ -192,10 +192,6 @@ public sealed class WmsController : ControllerBase
public Task<List<ContainerMaterial>> ContainerMaterials([FromQuery] string? q, [FromQuery] Guid? containerId) =>
_service.ContainerMaterials(q, containerId);
[HttpPost("container-materials")]
public async Task<IActionResult> SaveContainerMaterial([FromBody] BindMaterialRequest req) =>
Ok(await _service.BindMaterial(req, User.ActorName()));
[HttpPost("container-materials/bind")]
public async Task<IActionResult> BindMaterial([FromBody] BindMaterialRequest req) =>
Ok(await _service.BindMaterial(req, User.ActorName()));
@@ -7,7 +7,7 @@ namespace MiGu.Server.Dashboard;
public sealed class DashboardShortcutService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly RbacStore _rbac;
private static readonly JsonSerializerOptions JsonOpts = new()
@@ -15,7 +15,7 @@ public sealed class DashboardShortcutService
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
public DashboardShortcutService(PlatformDbContext db, RbacStore rbac)
public DashboardShortcutService(MiGuDbContext db, RbacStore rbac)
{
_db = db;
_rbac = rbac;
+2 -2
View File
@@ -76,7 +76,7 @@ public sealed class AlarmCollector
try
{
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<PlatformDbContext>();
var db = scope.ServiceProvider.GetRequiredService<MiGuDbContext>();
await ReconcileAsync(db, current, ct);
}
catch (Exception ex)
@@ -161,7 +161,7 @@ public sealed class AlarmCollector
}
}
private static async Task ReconcileAsync(PlatformDbContext db, Dictionary<int, CurrentAlarm> current, CancellationToken ct)
private static async Task ReconcileAsync(MiGuDbContext db, Dictionary<int, CurrentAlarm> current, CancellationToken ct)
{
var now = DateTimeOffset.UtcNow;
var active = await db.VehicleAlarms.Where(a => a.Status == "active").ToListAsync(ct);
+2 -2
View File
@@ -80,7 +80,7 @@ public sealed class CdmTaskSyncer
try
{
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<PlatformDbContext>();
var db = scope.ServiceProvider.GetRequiredService<MiGuDbContext>();
await UpsertAsync(db, dtos, ct);
}
catch (Exception ex)
@@ -126,7 +126,7 @@ public sealed class CdmTaskSyncer
}
}
private static async Task UpsertAsync(PlatformDbContext db, IReadOnlyList<CdmTaskDto> dtos, CancellationToken ct)
private static async Task UpsertAsync(MiGuDbContext db, IReadOnlyList<CdmTaskDto> dtos, CancellationToken ct)
{
var valid = dtos.Where(d => !string.IsNullOrWhiteSpace(d.id)).ToList();
if (valid.Count == 0) return;
+2 -2
View File
@@ -1,5 +1,5 @@
global using PlatformDbContext = MiGu.DB.Kernel.Context.MiGuDbContext;
global using EntityBase = MiGu.DB.Kernel.Entities.AggregateRoot;
global using MiGu.DB.Kernel.Context;
global using MiGu.DB.Kernel.Entities;
global using SimpleField = MiGu.DB.Domains.SimpleFields.SimpleField;
global using UserDashboardShortcut = MiGu.DB.Domains.Dashboard.UserDashboardShortcut;
global using Warehouse = MiGu.DB.Domains.Wms.Warehouse;
@@ -21,8 +21,4 @@ public static class PlatformPersistence
services.AddScoped<Dashboard.DashboardShortcutService>();
return services;
}
/// <summary>启动建库/迁移入口(内部即 MigrateMiGuDbAsyncMigrate + 基线 + DataMigrator)。</summary>
public static Task EnsurePlatformDatabaseAsync(this IServiceProvider services)
=> services.MigrateMiGuDbAsync();
}
+2 -1
View File
@@ -8,6 +8,7 @@ using MiGu.Server.Configs;
using MiGu.Server.Launcher;
using MiGu.Server.OpenApi;
using MiGu.Server.Ota;
using MiGu.DB.Kernel.Hosting;
using MiGu.Server.Persistence;
using Yarp.ReverseProxy.Transforms;
@@ -279,7 +280,7 @@ builder.Services.AddHostedService<MiGu.Server.Fleet.AlarmCollectorService>();
builder.Services.AddHttpClient(nameof(WatchDogClient));
var app = builder.Build();
await app.Services.EnsurePlatformDatabaseAsync();
await app.Services.MigrateMiGuDbAsync();
// 启动期主动构造 JwtIssuer / InternalTokenStore:让 secret 校验日志在请求来之前打印。
_ = app.Services.GetRequiredService<JwtIssuer>();
+2 -2
View File
@@ -110,8 +110,8 @@ AddPlatformPersistence(configuration) # 注册 AddMiGuDb + Wms/SimpleFields
builder.Build()
EnsurePlatformDatabaseAsync() # → MiGu.DB.MigrateMiGuDbAsync()
# Schema 初始化 + 可选 IDataMigrator
MigrateMiGuDbAsync() # Schema 初始化 + 可选 IDataMigrator
… 其余中间件 …
UseMiddleware<HttpActorContextMiddleware> # 请求级写入 IActorContext(审计戳)
@@ -6,9 +6,9 @@ namespace MiGu.Server.SimpleFields;
public sealed class SimpleFieldService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
public SimpleFieldService(PlatformDbContext db) => _db = db;
public SimpleFieldService(MiGuDbContext db) => _db = db;
public async Task<List<SimpleField>> ListAsync(string? fieldType = null, string? carType = null, string? q = null)
{
+1 -6
View File
@@ -20,7 +20,7 @@ public sealed record ContainerMaterialSnapshot(
public abstract record CommonRequest(Guid? Id, long? Version, bool IsLock, string Remark, string Extend);
public sealed record MasterDataRequest(
Guid? Id, long? Version, string Code, string Name, string Type, string Status, bool Enabled, int SortOrder,
Guid? Id, long? Version, string Code, string Name, string Type, bool Enabled, int SortOrder,
bool IsLock, string Remark, string Extend) : CommonRequest(Id, Version, IsLock, Remark, Extend);
public sealed record AreaRequest(
@@ -57,8 +57,3 @@ public sealed record ContainerLocationRequest(
public sealed record BindMaterialRequest(
Guid? Id, long? Version, Guid ContainerId, Guid MaterialId, string Source, string Reason,
bool IsLock, string Remark, string Extend) : CommonRequest(Id, Version, IsLock, Remark, Extend);
public sealed record ContainerMaterialRequest(
Guid? Id, long? Version, Guid ContainerId, Guid MaterialId, decimal Quantity, string BatchNo, string SerialNo,
string Status, DateTimeOffset? LoadedAt, DateTimeOffset? UnloadedAt, string Source, string Reason,
bool IsLock, string Remark, string Extend) : CommonRequest(Id, Version, IsLock, Remark, Extend);
+2 -2
View File
@@ -5,9 +5,9 @@ namespace MiGu.Server.Wms;
public sealed class WmsReferenceValidator
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
public WmsReferenceValidator(PlatformDbContext db)
public WmsReferenceValidator(MiGuDbContext db)
{
_db = db;
}
+24 -87
View File
@@ -10,14 +10,14 @@ namespace MiGu.Server.Wms;
public sealed class WmsService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly IUnitOfWork _uow;
private readonly IServiceProvider _services;
private readonly WmsReferenceValidator _refs;
private readonly JsonSerializerOptions _json = new(JsonSerializerDefaults.Web);
public WmsService(
PlatformDbContext db,
MiGuDbContext db,
IUnitOfWork uow,
IServiceProvider services,
WmsReferenceValidator refs)
@@ -158,7 +158,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Warehouses.Add(entity);
}
await EnsureUnique(_db.Warehouses, x => x.Code == req.Code && x.Id != entity.Id, "仓库编码已存在");
await Repo<Warehouse>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "仓库编码已存在");
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
entity.Type = req.Type.TrimOr("Default");
@@ -185,7 +185,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.WarehouseAreas.Add(entity);
}
await EnsureUnique(_db.WarehouseAreas, x => x.Code == req.Code && x.Id != entity.Id, "库区编码已存在");
await Repo<WarehouseArea>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "库区编码已存在");
entity.WarehouseId = warehouseId;
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
@@ -214,7 +214,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Storages.Add(entity);
}
await EnsureUnique(_db.Storages, x => x.Code == req.Code && x.Id != entity.Id, "库位编码已存在");
await Repo<Storage>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "库位编码已存在");
entity.AreaId = req.AreaId;
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
@@ -227,7 +227,7 @@ public sealed class WmsService
entity.SiteCode = req.SiteCode.TrimOr(entity.SiteId);
entity.Barcode = req.Barcode.TrimOr("");
entity.Capacity = 1;
var status = StorageStatuses.Normalize(req.Status);
var status = StorageStatuses.ParseOr(req.Status);
if (status == StorageStatuses.Disabled || req.Enabled == false)
entity.Status = req.Enabled ? status : StorageStatuses.Disabled;
else if (!string.IsNullOrWhiteSpace(req.Status) && StorageStatuses.All.Contains(status))
@@ -326,7 +326,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Containers.Add(entity);
}
await EnsureUnique(_db.Containers, x => x.Code == req.Code && x.Id != entity.Id, "容器编码已存在");
await Repo<Container>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "容器编码已存在");
entity.AreaId = req.AreaId;
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
@@ -353,7 +353,7 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.MaterialTypes.Add(entity);
}
await EnsureUnique(_db.MaterialTypes, x => x.Code == req.Code && x.Id != entity.Id, "物料类型编码已存在");
await Repo<MaterialType>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "物料类型编码已存在");
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
entity.Spec = req.Spec.TrimOr("");
@@ -378,9 +378,9 @@ public sealed class WmsService
StampCreate(entity, actor);
_db.Materials.Add(entity);
}
await EnsureUnique(_db.Materials, x => x.Code == req.Code && x.Id != entity.Id, "物料编码已存在");
await Repo<Material>().EnsureUniqueAsync(x => x.Code == req.Code && x.Id != entity.Id, "物料编码已存在");
if (!string.IsNullOrWhiteSpace(req.Barcode))
await EnsureUnique(_db.Materials, x => x.Barcode == req.Barcode && x.Id != entity.Id, "物料条码已存在");
await Repo<Material>().EnsureUniqueAsync(x => x.Barcode == req.Barcode && x.Id != entity.Id, "物料条码已存在");
entity.Code = req.Code.Trim();
entity.Name = req.Name.Trim();
entity.TypeCode = req.TypeCode.TrimOr("");
@@ -425,9 +425,9 @@ public sealed class WmsService
await _uow.SaveChangesAsync();
}
public async Task DeleteEntity<T>(Guid id, long? version, string actor) where T : EntityBase
public async Task DeleteEntity<T>(Guid id, long? version, string actor)
where T : class, IEntity<Guid>, ISoftDeletable, IVersioned, ILockable, IAuditable
{
var entity = await FindEditable<T>(id, version);
if (typeof(T) == typeof(WarehouseArea))
{
if (await _db.Storages.AnyAsync(x => x.AreaId == id))
@@ -444,10 +444,8 @@ public sealed class WmsService
if (await _db.ContainerMaterials.AnyAsync(x => x.MaterialId == id))
throw new InvalidOperationException("物料仍在绑定中,不能删除");
}
entity.IsDeleted = true;
entity.DeletedAt = DateTimeOffset.UtcNow;
entity.DeletedBy = actor;
entity.UpdatedBy = actor;
await Repo<T>().SoftDeleteAsync(id, version);
await _uow.SaveChangesAsync();
}
@@ -497,8 +495,7 @@ public sealed class WmsService
}
else
{
EnsureVersion(current, req.Version);
EnsureUnlocked(current);
await Repo<ContainerLocation>().GetEditableAsync(current.Id, req.Version);
}
current.LocationType = locationType;
@@ -540,7 +537,7 @@ public sealed class WmsService
{
var current = await _db.ContainerLocations.FirstOrDefaultAsync(x => x.ContainerId == containerId)
?? throw new InvalidOperationException("容器当前位置不存在");
EnsureUnlocked(current);
await Repo<ContainerLocation>().GetEditableAsync(current.Id, null);
Guid? fromStorageId = null;
if (current.LocationType == ContainerLocationTypes.Storage && Guid.TryParse(current.LocationId, out var fs))
fromStorageId = fs;
@@ -614,15 +611,9 @@ public sealed class WmsService
return current;
}
/// <summary>兼容旧接口:忽略数量,按实体绑定。</summary>
public Task<ContainerMaterial> SaveContainerMaterial(ContainerMaterialRequest req, string actor) =>
BindMaterial(new BindMaterialRequest(req.Id, req.Version, req.ContainerId, req.MaterialId, req.Source, req.Reason, req.IsLock, req.Remark, req.Extend), actor);
public async Task UnbindMaterial(Guid bindingId, string actor, string reason = "", bool archive = false)
{
var current = await _db.ContainerMaterials.FirstOrDefaultAsync(x => x.Id == bindingId)
?? throw new InvalidOperationException("绑定不存在");
EnsureUnlocked(current);
var current = await Repo<ContainerMaterial>().GetEditableAsync(bindingId, null);
var material = await _db.Materials.FirstOrDefaultAsync(x => x.Id == current.MaterialId);
var before = Snapshot(current);
var now = DateTimeOffset.UtcNow;
@@ -718,46 +709,6 @@ public sealed class WmsService
return wh;
}
public async Task MigrateLegacyAsync(string actor = "system")
{
var wh = await EnsureDefaultWarehouseAsync(actor);
var areas = await _db.WarehouseAreas.Where(x => x.WarehouseId == Guid.Empty).ToListAsync();
foreach (var a in areas)
a.WarehouseId = wh.Id;
var storages = await _db.Storages.ToListAsync();
foreach (var s in storages)
{
if (s.LevelNo <= 0) s.LevelNo = 1;
if (s.DepthNo <= 0) s.DepthNo = 1;
if (string.IsNullOrWhiteSpace(s.SiteCode)) s.SiteCode = s.SiteId;
if (!StorageStatuses.All.Contains(s.Status))
s.Status = StorageStatuses.Empty;
if (!s.Enabled) s.Status = StorageStatuses.Disabled;
}
var containers = await _db.Containers.ToListAsync();
foreach (var c in containers)
{
if (!ContainerStatuses.All.Contains(c.Status))
c.Status = ContainerStatuses.EmptyMaterial;
}
var binds = await _db.ContainerMaterials.ToListAsync();
foreach (var b in binds)
{
b.Quantity = 1;
if (b.BoundAt == default) b.BoundAt = b.LoadedAt == default ? DateTimeOffset.UtcNow : b.LoadedAt;
if (!ContainerMaterialStatuses.ActiveBind.Contains(b.Status))
b.Status = ContainerMaterialStatuses.Bound;
}
await _uow.SaveChangesAsync();
foreach (var s in storages.Where(x => x.Status != StorageStatuses.Disabled))
await SyncOccupancyStatus(storageId: s.Id);
}
public async Task<List<ContainerLocationHistory>> LocationHistory(Guid? containerId = null)
{
var rows = await (containerId.HasValue
@@ -857,16 +808,13 @@ public sealed class WmsService
});
}
private IEditableRepository<T> Repo<T>()
where T : class, IEntity<Guid>, ISoftDeletable, IVersioned, ILockable
=> _services.GetRequiredService<IEditableRepository<T>>();
private Task<T> FindEditable<T>(Guid id, long? version)
where T : class, IEntity<Guid>, ISoftDeletable, IVersioned, ILockable
=> _services.GetRequiredService<IEditableRepository<T>>().GetEditableAsync(id, version);
private static void EnsureVersion(EntityBase entity, long? version)
{
if (version.HasValue && entity.Version != version.Value)
throw new MiGu.DB.Abstractions.Exceptions.ConcurrencyConflictException(
entity.GetType().Name, entity.Id, version);
}
=> Repo<T>().GetEditableAsync(id, version);
private static bool IsUniqueConstraintViolation(DbUpdateException ex)
{
@@ -882,19 +830,13 @@ public sealed class WmsService
return false;
}
private static void EnsureUnlocked(EntityBase entity)
{
if (entity.IsLock)
throw new MiGu.DB.Abstractions.Exceptions.EntityLockedException(entity.GetType().Name, entity.Id);
}
private static void StampCreate(EntityBase entity, string actor)
private static void StampCreate(AggregateRoot entity, string actor)
{
entity.CreatedBy = actor;
entity.UpdatedBy = actor;
}
private void ApplyCommon(EntityBase entity, CommonRequest req, string actor)
private void ApplyCommon(AggregateRoot entity, CommonRequest req, string actor)
{
entity.IsLock = req.IsLock;
entity.Remark = req.Remark.TrimOr("");
@@ -902,11 +844,6 @@ public sealed class WmsService
entity.UpdatedBy = actor;
}
private static async Task EnsureUnique<T>(IQueryable<T> query, System.Linq.Expressions.Expression<Func<T, bool>> predicate, string message)
{
if (await query.AnyAsync(predicate)) throw new InvalidOperationException(message);
}
private string NormalizeExtend(string? extend)
{
if (string.IsNullOrWhiteSpace(extend)) return "{}";
-1
View File
@@ -16,4 +16,3 @@ global using WmsDefaults = MiGu.DB.Domains.Wms.WmsDefaults;
global using WmsTransportTaskStatuses = MiGu.DB.Domains.Transport.WmsTransportTaskStatuses;
global using WmsTransportTriggerTypes = MiGu.DB.Domains.Transport.WmsTransportTriggerTypes;
global using WmsReservationStatuses = MiGu.DB.Domains.Transport.WmsReservationStatuses;
global using WmsDispatchStatuses = MiGu.DB.Domains.Transport.WmsDispatchStatuses;
+2 -2
View File
@@ -6,10 +6,10 @@ namespace MiGu.Server.Wms;
public sealed class WmsTransportPlanner
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly JsonSerializerOptions _json = new(JsonSerializerDefaults.Web);
public WmsTransportPlanner(PlatformDbContext db) => _db = db;
public WmsTransportPlanner(MiGuDbContext db) => _db = db;
public async Task<TransportCandidatePreview> PreviewAsync(WmsTransportRequest request)
{
+4 -4
View File
@@ -7,12 +7,12 @@ namespace MiGu.Server.Wms;
public sealed class WmsTransportRuleService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly IEditableRepository<WmsTransportRule> _rules;
private readonly IUnitOfWork _uow;
public WmsTransportRuleService(
PlatformDbContext db,
MiGuDbContext db,
IEditableRepository<WmsTransportRule> rules,
IUnitOfWork uow)
{
@@ -71,13 +71,13 @@ public sealed class WmsTransportRuleService
await _uow.SaveChangesAsync();
}
private static void StampCreate(EntityBase entity, string actor)
private static void StampCreate(AggregateRoot entity, string actor)
{
entity.CreatedBy = actor;
entity.UpdatedBy = actor;
}
private static void ApplyCommon(EntityBase entity, CommonRequest req, string actor)
private static void ApplyCommon(AggregateRoot entity, CommonRequest req, string actor)
{
entity.IsLock = req.IsLock;
entity.Remark = req.Remark.TrimOr("");
+3 -3
View File
@@ -6,14 +6,14 @@ namespace MiGu.Server.Wms;
public sealed class WmsTransportTaskService
{
private readonly PlatformDbContext _db;
private readonly MiGuDbContext _db;
private readonly WmsTransportPlanner _planner;
private readonly WmsService _wms;
private readonly IWmsDispatchAdapter _dispatch;
private readonly JsonSerializerOptions _json = new(JsonSerializerDefaults.Web);
public WmsTransportTaskService(
PlatformDbContext db,
MiGuDbContext db,
WmsTransportPlanner planner,
WmsService wms,
IWmsDispatchAdapter dispatch)
@@ -331,7 +331,7 @@ public sealed class WmsTransportTaskService
GeneratedAt = DateTimeOffset.UtcNow
};
private static void StampCreate(EntityBase entity, string actor)
private static void StampCreate(AggregateRoot entity, string actor)
{
entity.CreatedBy = actor;
entity.UpdatedBy = actor;
@@ -206,7 +206,6 @@ export interface MasterDataPayload {
code: string
name: string
type: string
status: string
enabled: boolean
sortOrder: number
isLock: boolean
@@ -563,7 +563,7 @@ async function submitDialog() {
...masterForm,
barcode: containerBarcode.value,
length: 0, width: 0, height: 0,
status: 'EmptyMaterial'
status: containers.value.find((c) => c.id === masterForm.id)?.status ?? 'EmptyMaterial'
})
}
else if (kind === 'storage') await wmsApi.saveStorage(storageForm)
@@ -683,7 +683,6 @@ function baseMaster(row?: WarehouseArea | Container): MasterDataPayload {
code: row?.code ?? '',
name: row?.name ?? '',
type: 'type' in (row ?? {}) ? (row as WarehouseArea).type : (row as Container | undefined)?.containerType ?? 'Box',
status: (row as Container | undefined)?.status ?? 'Idle',
enabled: row?.enabled ?? true,
sortOrder: (row as WarehouseArea | undefined)?.sortOrder ?? 0
}