bakery-erp / src /BakeryErp.Infrastructure /Repositories /OcrDocumentRepository.cs
Neil67's picture
Deploy Bakery ERP Space
13240d3
Raw
History Blame Contribute Delete
6.05 kB
using BakeryErp.Infrastructure.Database;
namespace BakeryErp.Infrastructure.Repositories;
public sealed class OcrDocumentRepository
{
private readonly DatabaseOptions _options;
public OcrDocumentRepository(DatabaseOptions options)
{
_options = options;
}
public IReadOnlyList<LocalOcrDocument> List()
{
return LocalDataStoreFile.Load(_options)
.OcrDocuments
.OrderByDescending(static document => document.CreatedAt)
.ToList();
}
public LocalOcrDocument? Find(Guid id)
{
return LocalDataStoreFile.Load(_options)
.OcrDocuments
.FirstOrDefault(document => document.Id == id);
}
public OcrReport GetReport()
{
var documents = LocalDataStoreFile.Load(_options).OcrDocuments;
return new OcrReport(
documents.Count,
documents.Count(static document => document.Status == LocalOcrStatus.Uploaded),
documents.Count(static document => document.Status == LocalOcrStatus.Recognized),
documents.Count(static document => document.Status == LocalOcrStatus.MappingRequired),
documents.Count(static document => document.Status == LocalOcrStatus.Confirmed),
documents.Count(static document => document.Status == LocalOcrStatus.ConvertedToReceipt),
documents.Count(static document => document.Status == LocalOcrStatus.Failed),
documents.Sum(static document => document.TotalAmount ?? 0));
}
public SaveOcrDocumentResult Save(LocalOcrDocument document)
{
var store = LocalDataStoreFile.Load(_options);
var documentNumber = document.DocumentNumber.Trim().ToUpperInvariant();
if (string.IsNullOrWhiteSpace(documentNumber))
{
return SaveOcrDocumentResult.ValidationError("單據編號為必填。");
}
var duplicatedNumber = store.OcrDocuments.Any(existing =>
existing.Id != document.Id &&
string.Equals(existing.DocumentNumber, documentNumber, StringComparison.OrdinalIgnoreCase));
if (duplicatedNumber)
{
return SaveOcrDocumentResult.ValidationError("單據編號已存在,請改用其他編號。");
}
var existingDocument = store.OcrDocuments.FirstOrDefault(existing => existing.Id == document.Id);
if (existingDocument is null)
{
document.Id = document.Id == Guid.Empty ? Guid.NewGuid() : document.Id;
document.DocumentNumber = documentNumber;
document.FileName = BlankToEmpty(document.FileName);
document.SupplierName = BlankToNull(document.SupplierName);
document.RawText = BlankToNull(document.RawText);
document.RecognizedItems = BlankToNull(document.RecognizedItems);
document.ReviewNote = BlankToNull(document.ReviewNote);
document.CreatedAt = DateTime.UtcNow;
store.OcrDocuments.Add(document);
}
else
{
existingDocument.DocumentNumber = documentNumber;
existingDocument.FileName = BlankToEmpty(document.FileName);
existingDocument.SupplierName = BlankToNull(document.SupplierName);
existingDocument.DocumentDate = document.DocumentDate;
existingDocument.Status = document.Status;
existingDocument.TotalAmount = document.TotalAmount;
existingDocument.RawText = BlankToNull(document.RawText);
existingDocument.RecognizedItems = BlankToNull(document.RecognizedItems);
existingDocument.ReviewNote = BlankToNull(document.ReviewNote);
existingDocument.UpdatedAt = DateTime.UtcNow;
}
LocalDataStoreFile.Save(_options, store);
return SaveOcrDocumentResult.Success();
}
public void Review(Guid id, bool approved)
{
var store = LocalDataStoreFile.Load(_options);
var document = store.OcrDocuments.FirstOrDefault(existing => existing.Id == id);
if (document is null)
{
return;
}
document.Status = approved ? LocalOcrStatus.Confirmed : LocalOcrStatus.MappingRequired;
document.ReviewedAt = DateTime.UtcNow;
document.UpdatedAt = DateTime.UtcNow;
LocalDataStoreFile.Save(_options, store);
}
public void ConvertToReceipt(Guid id)
{
var store = LocalDataStoreFile.Load(_options);
var document = store.OcrDocuments.FirstOrDefault(existing => existing.Id == id);
if (document is null)
{
return;
}
document.Status = LocalOcrStatus.ConvertedToReceipt;
document.UpdatedAt = DateTime.UtcNow;
LocalDataStoreFile.Save(_options, store);
}
public static string GetStatusName(LocalOcrStatus status)
{
return status switch
{
LocalOcrStatus.Uploaded => "已上傳",
LocalOcrStatus.Recognized => "已辨識",
LocalOcrStatus.MappingRequired => "待對應",
LocalOcrStatus.Confirmed => "已確認",
LocalOcrStatus.ConvertedToReceipt => "已轉進貨",
LocalOcrStatus.Failed => "失敗",
_ => status.ToString()
};
}
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 OcrReport(
int TotalCount,
int UploadedCount,
int RecognizedCount,
int MappingRequiredCount,
int ConfirmedCount,
int ConvertedToReceiptCount,
int FailedCount,
decimal TotalAmount);
public sealed record SaveOcrDocumentResult(bool IsSuccess, string? ErrorMessage)
{
public static SaveOcrDocumentResult Success() => new(true, null);
public static SaveOcrDocumentResult ValidationError(string message) => new(false, message);
}