Neil67's picture
Deploy Bakery ERP Space
13240d3
Raw
History Blame Contribute Delete
7.96 kB
using BakeryErp.Infrastructure.Database;
namespace BakeryErp.Infrastructure.Repositories;
public sealed class TransferRepository
{
private readonly DatabaseOptions _options;
public TransferRepository(DatabaseOptions options)
{
_options = options;
}
public IReadOnlyList<LocalTransferOrder> List()
{
return LocalDataStoreFile.Load(_options)
.TransferOrders
.OrderByDescending(static order => order.RequestDate)
.ThenBy(static order => order.TransferNumber)
.ToList();
}
public LocalTransferOrder? Find(Guid id)
{
return LocalDataStoreFile.Load(_options)
.TransferOrders
.FirstOrDefault(order => order.Id == id);
}
public TransferReport GetReport()
{
var orders = LocalDataStoreFile.Load(_options).TransferOrders;
return new TransferReport(
orders.Count,
orders.Count(static order => order.Status == LocalTransferStatus.StoreRequested),
orders.Count(static order => order.Status == LocalTransferStatus.Prepared),
orders.Count(static order => order.Status == LocalTransferStatus.InTransit),
orders.Count(static order => order.Status == LocalTransferStatus.Completed),
orders.Count(static order => order.Status == LocalTransferStatus.Discrepancy),
orders.Sum(static order => Math.Abs(order.DifferenceQuantity)));
}
public SaveTransferResult Save(LocalTransferOrder order)
{
var store = LocalDataStoreFile.Load(_options);
var transferNumber = order.TransferNumber.Trim().ToUpperInvariant();
if (string.IsNullOrWhiteSpace(transferNumber) ||
string.IsNullOrWhiteSpace(order.StoreName) ||
string.IsNullOrWhiteSpace(order.FromWarehouseName) ||
string.IsNullOrWhiteSpace(order.ToWarehouseName) ||
string.IsNullOrWhiteSpace(order.ItemName) ||
string.IsNullOrWhiteSpace(order.Unit))
{
return SaveTransferResult.ValidationError("調撥單號、門市、倉庫、品項與單位為必填。");
}
if (order.RequestedQuantity <= 0)
{
return SaveTransferResult.ValidationError("叫貨數量需大於 0。");
}
var duplicatedNumber = store.TransferOrders.Any(existing =>
existing.Id != order.Id &&
string.Equals(existing.TransferNumber, transferNumber, StringComparison.OrdinalIgnoreCase));
if (duplicatedNumber)
{
return SaveTransferResult.ValidationError("調撥單號已存在,請改用其他單號。");
}
var existingOrder = store.TransferOrders.FirstOrDefault(existing => existing.Id == order.Id);
if (existingOrder is null)
{
order.Id = order.Id == Guid.Empty ? Guid.NewGuid() : order.Id;
order.TransferNumber = transferNumber;
order.StoreName = order.StoreName.Trim();
order.FromWarehouseName = order.FromWarehouseName.Trim();
order.ToWarehouseName = order.ToWarehouseName.Trim();
order.ItemSku = BlankToEmpty(order.ItemSku).ToUpperInvariant();
order.ItemName = order.ItemName.Trim();
order.Unit = order.Unit.Trim();
order.Note = BlankToNull(order.Note);
order.Status = LocalTransferStatus.StoreRequested;
order.CreatedAt = DateTime.UtcNow;
store.TransferOrders.Add(order);
}
else
{
if (existingOrder.Status is LocalTransferStatus.InTransit or LocalTransferStatus.Completed)
{
return SaveTransferResult.ValidationError("配送中或已完成的調撥單不可編輯。");
}
existingOrder.TransferNumber = transferNumber;
existingOrder.StoreName = order.StoreName.Trim();
existingOrder.FromWarehouseName = order.FromWarehouseName.Trim();
existingOrder.ToWarehouseName = order.ToWarehouseName.Trim();
existingOrder.ItemSku = BlankToEmpty(order.ItemSku).ToUpperInvariant();
existingOrder.ItemName = order.ItemName.Trim();
existingOrder.RequestedQuantity = order.RequestedQuantity;
existingOrder.PreparedQuantity = order.PreparedQuantity;
existingOrder.ShippedQuantity = order.ShippedQuantity;
existingOrder.ReceivedQuantity = order.ReceivedQuantity;
existingOrder.DifferenceQuantity = order.DifferenceQuantity;
existingOrder.Unit = order.Unit.Trim();
existingOrder.RequestDate = order.RequestDate;
existingOrder.Note = BlankToNull(order.Note);
existingOrder.UpdatedAt = DateTime.UtcNow;
}
LocalDataStoreFile.Save(_options, store);
return SaveTransferResult.Success();
}
public void Prepare(Guid id, decimal preparedQuantity)
{
Update(id, order =>
{
order.PreparedQuantity = preparedQuantity <= 0 ? order.RequestedQuantity : preparedQuantity;
order.Status = LocalTransferStatus.Prepared;
order.PreparedAt = DateTime.UtcNow;
});
}
public void Ship(Guid id)
{
Update(id, order =>
{
order.ShippedQuantity = order.PreparedQuantity <= 0 ? order.RequestedQuantity : order.PreparedQuantity;
order.Status = LocalTransferStatus.InTransit;
order.ShippedAt = DateTime.UtcNow;
});
}
public void Receive(Guid id, decimal receivedQuantity)
{
Update(id, order =>
{
order.ReceivedQuantity = receivedQuantity;
order.DifferenceQuantity = order.ReceivedQuantity - order.ShippedQuantity;
order.Status = order.DifferenceQuantity == 0 ? LocalTransferStatus.Completed : LocalTransferStatus.Discrepancy;
order.ReceivedAt = DateTime.UtcNow;
});
}
public void Cancel(Guid id)
{
Update(id, order =>
{
if (order.Status != LocalTransferStatus.Completed)
{
order.Status = LocalTransferStatus.Cancelled;
}
});
}
public static string GetStatusName(LocalTransferStatus status)
{
return status switch
{
LocalTransferStatus.Draft => "草稿",
LocalTransferStatus.StoreRequested => "門市叫貨",
LocalTransferStatus.Prepared => "已備貨",
LocalTransferStatus.InTransit => "配送中",
LocalTransferStatus.Completed => "已完成",
LocalTransferStatus.Discrepancy => "有差異",
LocalTransferStatus.Cancelled => "已取消",
_ => status.ToString()
};
}
private void Update(Guid id, Action<LocalTransferOrder> update)
{
var store = LocalDataStoreFile.Load(_options);
var order = store.TransferOrders.FirstOrDefault(existing => existing.Id == id);
if (order is null)
{
return;
}
update(order);
order.UpdatedAt = DateTime.UtcNow;
LocalDataStoreFile.Save(_options, store);
}
private static string BlankToEmpty(string? value)
{
return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim();
}
private static string? BlankToNull(string? value)
{
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}
}
public sealed record TransferReport(
int OrderCount,
int StoreRequestedCount,
int PreparedCount,
int InTransitCount,
int CompletedCount,
int DiscrepancyCount,
decimal DifferenceQuantityTotal);
public sealed record SaveTransferResult(bool IsSuccess, string? ErrorMessage)
{
public static SaveTransferResult Success() => new(true, null);
public static SaveTransferResult ValidationError(string message) => new(false, message);
}