Spaces:
Sleeping
Sleeping
| using BakeryErp.Infrastructure.Database; | |
| namespace BakeryErp.Infrastructure.Repositories; | |
| public sealed class ItemRepository | |
| { | |
| private readonly DatabaseOptions _options; | |
| public ItemRepository(DatabaseOptions options) | |
| { | |
| _options = options; | |
| } | |
| public IReadOnlyList<LocalItem> List() => LocalDataStoreFile.Load(_options).Items | |
| .OrderByDescending(static item => item.IsActive) | |
| .ThenBy(static item => item.Sku) | |
| .ToList(); | |
| public LocalItem? Find(Guid id) => LocalDataStoreFile.Load(_options).Items.FirstOrDefault(item => item.Id == id); | |
| public SaveMasterDataResult Save(LocalItem item) | |
| { | |
| var store = LocalDataStoreFile.Load(_options); | |
| var sku = item.Sku?.Trim().ToUpperInvariant() ?? string.Empty; | |
| var name = item.Name?.Trim() ?? string.Empty; | |
| var categoryName = item.CategoryName?.Trim() ?? string.Empty; | |
| var baseUnit = item.BaseUnit?.Trim() ?? string.Empty; | |
| if (string.IsNullOrWhiteSpace(sku) || string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(baseUnit)) | |
| { | |
| return SaveMasterDataResult.ValidationError("品項代號、名稱與基本單位為必填。"); | |
| } | |
| if (store.Items.Any(existing => existing.Id != item.Id && string.Equals(existing.Sku, sku, StringComparison.OrdinalIgnoreCase))) | |
| { | |
| return SaveMasterDataResult.ValidationError("品項代號已存在。"); | |
| } | |
| var existingItem = store.Items.FirstOrDefault(existing => existing.Id == item.Id); | |
| if (existingItem is null) | |
| { | |
| item.Id = item.Id == Guid.Empty ? Guid.NewGuid() : item.Id; | |
| item.Sku = sku; | |
| item.Name = name; | |
| item.CategoryName = categoryName; | |
| item.BaseUnit = baseUnit; | |
| item.CreatedAt = DateTime.UtcNow; | |
| item.IsActive = true; | |
| store.Items.Add(item); | |
| } | |
| else | |
| { | |
| existingItem.Sku = sku; | |
| existingItem.Name = name; | |
| existingItem.ItemType = item.ItemType; | |
| existingItem.CategoryName = categoryName; | |
| existingItem.BaseUnit = baseUnit; | |
| existingItem.SafetyStockQuantity = item.SafetyStockQuantity; | |
| existingItem.ShelfLifeDays = item.ShelfLifeDays; | |
| existingItem.UpdatedAt = DateTime.UtcNow; | |
| } | |
| LocalDataStoreFile.Save(_options, store); | |
| return SaveMasterDataResult.Success(); | |
| } | |
| public void SetActive(Guid id, bool isActive) | |
| { | |
| var store = LocalDataStoreFile.Load(_options); | |
| var item = store.Items.FirstOrDefault(existing => existing.Id == id); | |
| if (item is null) | |
| { | |
| return; | |
| } | |
| item.IsActive = isActive; | |
| item.UpdatedAt = DateTime.UtcNow; | |
| LocalDataStoreFile.Save(_options, store); | |
| } | |
| } | |
| public sealed class StoreRepository | |
| { | |
| private readonly DatabaseOptions _options; | |
| public StoreRepository(DatabaseOptions options) | |
| { | |
| _options = options; | |
| } | |
| public IReadOnlyList<LocalStore> List() => LocalDataStoreFile.Load(_options).Stores | |
| .OrderByDescending(static store => store.IsActive) | |
| .ThenBy(static store => store.Code) | |
| .ToList(); | |
| public LocalStore? Find(Guid id) => LocalDataStoreFile.Load(_options).Stores.FirstOrDefault(store => store.Id == id); | |
| public SaveMasterDataResult Save(LocalStore storeInfo) | |
| { | |
| var store = LocalDataStoreFile.Load(_options); | |
| var code = storeInfo.Code?.Trim().ToUpperInvariant() ?? string.Empty; | |
| var name = storeInfo.Name?.Trim() ?? string.Empty; | |
| if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(name)) | |
| { | |
| return SaveMasterDataResult.ValidationError("門市代號與名稱為必填。"); | |
| } | |
| if (store.Stores.Any(existing => existing.Id != storeInfo.Id && string.Equals(existing.Code, code, StringComparison.OrdinalIgnoreCase))) | |
| { | |
| return SaveMasterDataResult.ValidationError("門市代號已存在。"); | |
| } | |
| var existingStore = store.Stores.FirstOrDefault(existing => existing.Id == storeInfo.Id); | |
| if (existingStore is null) | |
| { | |
| storeInfo.Id = storeInfo.Id == Guid.Empty ? Guid.NewGuid() : storeInfo.Id; | |
| storeInfo.Code = code; | |
| storeInfo.Name = name; | |
| storeInfo.Phone = BlankToNull(storeInfo.Phone); | |
| storeInfo.Address = BlankToNull(storeInfo.Address); | |
| storeInfo.CreatedAt = DateTime.UtcNow; | |
| storeInfo.IsActive = true; | |
| store.Stores.Add(storeInfo); | |
| } | |
| else | |
| { | |
| existingStore.Code = code; | |
| existingStore.Name = name; | |
| existingStore.StoreType = storeInfo.StoreType; | |
| existingStore.Phone = BlankToNull(storeInfo.Phone); | |
| existingStore.Address = BlankToNull(storeInfo.Address); | |
| existingStore.UpdatedAt = DateTime.UtcNow; | |
| } | |
| LocalDataStoreFile.Save(_options, store); | |
| return SaveMasterDataResult.Success(); | |
| } | |
| public void SetActive(Guid id, bool isActive) | |
| { | |
| var store = LocalDataStoreFile.Load(_options); | |
| var storeInfo = store.Stores.FirstOrDefault(existing => existing.Id == id); | |
| if (storeInfo is null) | |
| { | |
| return; | |
| } | |
| storeInfo.IsActive = isActive; | |
| storeInfo.UpdatedAt = DateTime.UtcNow; | |
| LocalDataStoreFile.Save(_options, store); | |
| } | |
| private static string? BlankToNull(string? value) => string.IsNullOrWhiteSpace(value) ? null : value.Trim(); | |
| } | |
| public sealed class WarehouseRepository | |
| { | |
| private readonly DatabaseOptions _options; | |
| public WarehouseRepository(DatabaseOptions options) | |
| { | |
| _options = options; | |
| } | |
| public IReadOnlyList<LocalWarehouse> List() => LocalDataStoreFile.Load(_options).Warehouses | |
| .OrderByDescending(static warehouse => warehouse.IsActive) | |
| .ThenBy(static warehouse => warehouse.Code) | |
| .ToList(); | |
| public LocalWarehouse? Find(Guid id) => LocalDataStoreFile.Load(_options).Warehouses.FirstOrDefault(warehouse => warehouse.Id == id); | |
| public IReadOnlyList<string> ActiveStoreNames() => LocalDataStoreFile.Load(_options).Stores | |
| .Where(static store => store.IsActive) | |
| .Select(static store => store.Name) | |
| .ToList(); | |
| public SaveMasterDataResult Save(LocalWarehouse warehouse) | |
| { | |
| var store = LocalDataStoreFile.Load(_options); | |
| var code = warehouse.Code?.Trim().ToUpperInvariant() ?? string.Empty; | |
| var name = warehouse.Name?.Trim() ?? string.Empty; | |
| if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(name)) | |
| { | |
| return SaveMasterDataResult.ValidationError("倉庫代號與名稱為必填。"); | |
| } | |
| if (store.Warehouses.Any(existing => existing.Id != warehouse.Id && string.Equals(existing.Code, code, StringComparison.OrdinalIgnoreCase))) | |
| { | |
| return SaveMasterDataResult.ValidationError("倉庫代號已存在。"); | |
| } | |
| var existingWarehouse = store.Warehouses.FirstOrDefault(existing => existing.Id == warehouse.Id); | |
| if (existingWarehouse is null) | |
| { | |
| warehouse.Id = warehouse.Id == Guid.Empty ? Guid.NewGuid() : warehouse.Id; | |
| warehouse.Code = code; | |
| warehouse.Name = name; | |
| warehouse.StoreName = BlankToNull(warehouse.StoreName); | |
| warehouse.CreatedAt = DateTime.UtcNow; | |
| warehouse.IsActive = true; | |
| store.Warehouses.Add(warehouse); | |
| } | |
| else | |
| { | |
| existingWarehouse.Code = code; | |
| existingWarehouse.Name = name; | |
| existingWarehouse.StoreName = BlankToNull(warehouse.StoreName); | |
| existingWarehouse.WarehouseType = warehouse.WarehouseType; | |
| existingWarehouse.UpdatedAt = DateTime.UtcNow; | |
| } | |
| LocalDataStoreFile.Save(_options, store); | |
| return SaveMasterDataResult.Success(); | |
| } | |
| public void SetActive(Guid id, bool isActive) | |
| { | |
| var store = LocalDataStoreFile.Load(_options); | |
| var warehouse = store.Warehouses.FirstOrDefault(existing => existing.Id == id); | |
| if (warehouse is null) | |
| { | |
| return; | |
| } | |
| warehouse.IsActive = isActive; | |
| warehouse.UpdatedAt = DateTime.UtcNow; | |
| LocalDataStoreFile.Save(_options, store); | |
| } | |
| private static string? BlankToNull(string? value) => string.IsNullOrWhiteSpace(value) ? null : value.Trim(); | |
| } | |
| public sealed record SaveMasterDataResult(bool IsSuccess, string? ErrorMessage) | |
| { | |
| public static SaveMasterDataResult Success() => new(true, null); | |
| public static SaveMasterDataResult ValidationError(string message) => new(false, message); | |
| } | |