Files
EmailBill/Application/TransactionApplication.cs

388 lines
12 KiB
C#
Raw Permalink Normal View History

2026-02-10 17:49:19 +08:00
using Application.Dto.Transaction;
using Service.AI;
namespace Application;
/// <summary>
/// 交易应用服务接口
/// </summary>
public interface ITransactionApplication
{
/// <summary>
/// 获取交易记录列表(分页)
/// </summary>
Task<PagedResult<TransactionResponse>> GetListAsync(TransactionQueryRequest request);
/// <summary>
/// 根据ID获取交易记录详情
/// </summary>
Task<TransactionResponse> GetByIdAsync(long id);
/// <summary>
/// 创建交易记录
/// </summary>
Task CreateAsync(CreateTransactionRequest request);
/// <summary>
/// 更新交易记录
/// </summary>
Task UpdateAsync(UpdateTransactionRequest request);
/// <summary>
/// 删除交易记录
/// </summary>
Task DeleteByIdAsync(long id);
/// <summary>
/// 根据邮件ID获取交易记录列表
/// </summary>
Task<List<TransactionResponse>> GetByEmailIdAsync(long emailId);
/// <summary>
/// 根据日期获取交易记录列表
/// </summary>
Task<List<TransactionResponse>> GetByDateAsync(DateTime date);
/// <summary>
/// 获取未确认的交易记录列表
/// </summary>
Task<List<TransactionResponse>> GetUnconfirmedListAsync();
/// <summary>
/// 获取未确认的交易记录数量
/// </summary>
Task<int> GetUnconfirmedCountAsync();
/// <summary>
/// 获取未分类的账单数量
/// </summary>
Task<int> GetUnclassifiedCountAsync();
/// <summary>
/// 获取未分类的账单列表
/// </summary>
Task<List<TransactionResponse>> GetUnclassifiedAsync(int pageSize);
/// <summary>
/// 确认所有未确认的记录
/// </summary>
Task<int> ConfirmAllUnconfirmedAsync(long[] ids);
/// <summary>
/// 智能分类AI分类支持回调
/// </summary>
Task SmartClassifyAsync(long[] transactionIds, Action<(string type, string data)> onChunk);
/// <summary>
/// 一句话录账解析
/// </summary>
Task<TransactionParseResult?> ParseOneLineAsync(string text);
/// <summary>
/// 账单分析AI分析支持回调
/// </summary>
Task AnalyzeBillAsync(string userInput, Action<string> onChunk);
/// <summary>
/// 批量更新分类
/// </summary>
Task<int> BatchUpdateClassifyAsync(List<BatchUpdateClassifyItem> items);
/// <summary>
/// 按摘要批量更新分类
/// </summary>
Task<int> BatchUpdateByReasonAsync(BatchUpdateByReasonRequest request);
}
/// <summary>
/// 交易应用服务实现
/// </summary>
public class TransactionApplication(
ITransactionRecordRepository transactionRepository,
2026-02-11 13:00:01 +08:00
ISmartHandleService smartHandleService
2026-02-10 17:49:19 +08:00
) : ITransactionApplication
{
public async Task<PagedResult<TransactionResponse>> GetListAsync(TransactionQueryRequest request)
{
var classifies = string.IsNullOrWhiteSpace(request.Classify)
? null
: request.Classify.Split(',', StringSplitOptions.RemoveEmptyEntries);
TransactionType? transactionType = request.Type.HasValue ? (TransactionType)request.Type.Value : null;
var list = await transactionRepository.QueryAsync(
year: request.Year,
month: request.Month,
startDate: request.StartDate,
endDate: request.EndDate,
type: transactionType,
classifies: classifies,
searchKeyword: request.SearchKeyword,
reason: request.Reason,
pageIndex: request.PageIndex,
pageSize: request.PageSize,
sortByAmount: request.SortByAmount);
var total = await transactionRepository.CountAsync(
year: request.Year,
month: request.Month,
startDate: request.StartDate,
endDate: request.EndDate,
type: transactionType,
classifies: classifies,
searchKeyword: request.SearchKeyword,
reason: request.Reason);
return new PagedResult<TransactionResponse>
{
Data = list.Select(MapToResponse).ToArray(),
Total = (int)total
};
}
public async Task<TransactionResponse> GetByIdAsync(long id)
{
var transaction = await transactionRepository.GetByIdAsync(id);
if (transaction == null)
{
throw new NotFoundException("交易记录不存在");
}
return MapToResponse(transaction);
}
public async Task CreateAsync(CreateTransactionRequest request)
{
// 解析日期字符串
if (!DateTime.TryParse(request.OccurredAt, out var occurredAt))
{
throw new ValidationException("交易时间格式不正确");
}
var transaction = new TransactionRecord
{
OccurredAt = occurredAt,
Reason = request.Reason ?? string.Empty,
Amount = request.Amount,
Type = request.Type,
Classify = request.Classify ?? string.Empty,
ImportFrom = "手动录入",
ImportNo = Guid.NewGuid().ToString("N"),
Card = "手动",
EmailMessageId = 0
};
var result = await transactionRepository.AddAsync(transaction);
if (!result)
{
throw new BusinessException("创建交易记录失败");
}
}
public async Task UpdateAsync(UpdateTransactionRequest request)
{
var transaction = await transactionRepository.GetByIdAsync(request.Id);
if (transaction == null)
{
throw new NotFoundException("交易记录不存在");
}
// 更新可编辑字段
transaction.Reason = request.Reason ?? string.Empty;
transaction.Amount = request.Amount;
transaction.Balance = request.Balance;
transaction.Type = request.Type;
transaction.Classify = request.Classify ?? string.Empty;
// 更新交易时间
if (!string.IsNullOrEmpty(request.OccurredAt) && DateTime.TryParse(request.OccurredAt, out var occurredAt))
{
transaction.OccurredAt = occurredAt;
}
// 清除待确认状态
transaction.UnconfirmedClassify = null;
transaction.UnconfirmedType = null;
var success = await transactionRepository.UpdateAsync(transaction);
if (!success)
{
throw new BusinessException("更新交易记录失败");
}
}
public async Task DeleteByIdAsync(long id)
{
var success = await transactionRepository.DeleteAsync(id);
if (!success)
{
throw new BusinessException("删除交易记录失败,记录不存在");
}
}
public async Task<List<TransactionResponse>> GetByEmailIdAsync(long emailId)
{
var transactions = await transactionRepository.GetByEmailIdAsync(emailId);
return transactions.Select(MapToResponse).ToList();
}
public async Task<List<TransactionResponse>> GetByDateAsync(DateTime date)
{
// 获取当天的开始和结束时间
var startDate = date.Date;
var endDate = startDate.AddDays(1);
var records = await transactionRepository.QueryAsync(startDate: startDate, endDate: endDate);
return records.Select(MapToResponse).ToList();
}
public async Task<List<TransactionResponse>> GetUnconfirmedListAsync()
{
var records = await transactionRepository.GetUnconfirmedRecordsAsync();
return records.Select(MapToResponse).ToList();
}
public async Task<int> GetUnconfirmedCountAsync()
{
var records = await transactionRepository.GetUnconfirmedRecordsAsync();
return records.Count;
}
public async Task<int> GetUnclassifiedCountAsync()
{
return (int)await transactionRepository.CountAsync();
}
public async Task<List<TransactionResponse>> GetUnclassifiedAsync(int pageSize)
{
var records = await transactionRepository.GetUnclassifiedAsync(pageSize);
return records.Select(MapToResponse).ToList();
}
public async Task<int> ConfirmAllUnconfirmedAsync(long[] ids)
{
if (ids == null || ids.Length == 0)
{
throw new ValidationException("请提供要确认的交易ID列表");
}
return await transactionRepository.ConfirmAllUnconfirmedAsync(ids);
}
public async Task SmartClassifyAsync(long[] transactionIds, Action<(string type, string data)> onChunk)
{
// 验证
if (transactionIds == null || transactionIds.Length == 0)
{
throw new ValidationException("请提供要分类的账单ID");
}
// 调用Service进行智能分类
await smartHandleService.SmartClassifyAsync(transactionIds, onChunk);
}
public async Task<TransactionParseResult?> ParseOneLineAsync(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
throw new ValidationException("解析文本不能为空");
}
var result = await smartHandleService.ParseOneLineBillAsync(text);
if (result == null)
{
throw new BusinessException("AI解析失败");
}
return result;
}
public async Task AnalyzeBillAsync(string userInput, Action<string> onChunk)
{
if (string.IsNullOrWhiteSpace(userInput))
{
throw new ValidationException("请输入分析内容");
}
await smartHandleService.AnalyzeBillAsync(userInput, onChunk);
}
public async Task<int> BatchUpdateClassifyAsync(List<BatchUpdateClassifyItem> items)
{
if (items == null || items.Count == 0)
{
throw new ValidationException("请提供要更新的记录");
}
var successCount = 0;
foreach (var item in items)
{
var record = await transactionRepository.GetByIdAsync(item.Id);
if (record != null)
{
record.Classify = item.Classify ?? string.Empty;
// 如果提供了Type也更新Type
if (item.Type.HasValue)
{
record.Type = item.Type.Value;
}
// 清除待确认状态
if (!string.IsNullOrEmpty(record.Classify))
{
record.UnconfirmedClassify = null;
}
if (item.Type.HasValue && record.Type == item.Type.Value)
{
record.UnconfirmedType = null;
}
var success = await transactionRepository.UpdateAsync(record);
if (success)
{
successCount++;
}
}
}
return successCount;
}
public async Task<int> BatchUpdateByReasonAsync(BatchUpdateByReasonRequest request)
{
if (string.IsNullOrWhiteSpace(request.Reason))
{
throw new ValidationException("摘要不能为空");
}
if (string.IsNullOrWhiteSpace(request.Classify))
{
throw new ValidationException("分类不能为空");
}
return await transactionRepository.BatchUpdateByReasonAsync(
request.Reason,
request.Type,
request.Classify);
}
private static TransactionResponse MapToResponse(TransactionRecord record)
{
return new TransactionResponse
{
Id = record.Id,
OccurredAt = record.OccurredAt,
Reason = record.Reason,
Amount = record.Amount,
Balance = record.Balance,
Type = record.Type,
Classify = record.Classify,
UnconfirmedClassify = record.UnconfirmedClassify,
UnconfirmedType = record.UnconfirmedType
};
}
}