Store user-provided parsing notes in the database so they persist across parsing attempts. Notes are displayed in Receipt Information and pre-populated in the textarea for future parses. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
128 lines
4.3 KiB
C#
128 lines
4.3 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using MoneyMap.Data;
|
|
using MoneyMap.Models;
|
|
using MoneyMap.Services;
|
|
|
|
namespace MoneyMap.Pages
|
|
{
|
|
public class ViewReceiptModel : PageModel
|
|
{
|
|
private readonly MoneyMapContext _db;
|
|
private readonly IReceiptManager _receiptManager;
|
|
private readonly IEnumerable<IReceiptParser> _parsers;
|
|
private readonly IConfiguration _config;
|
|
|
|
public ViewReceiptModel(
|
|
MoneyMapContext db,
|
|
IReceiptManager receiptManager,
|
|
IEnumerable<IReceiptParser> parsers,
|
|
IConfiguration config)
|
|
{
|
|
_db = db;
|
|
_receiptManager = receiptManager;
|
|
_parsers = parsers;
|
|
_config = config;
|
|
}
|
|
|
|
public Receipt? Receipt { get; set; }
|
|
public List<ReceiptLineItem> LineItems { get; set; } = new();
|
|
public List<ReceiptParseLog> ParseLogs { get; set; } = new();
|
|
public List<ParserOption> AvailableParsers { get; set; } = new();
|
|
public string ReceiptUrl { get; set; } = "";
|
|
public string SelectedModel => _config["AI:ReceiptParsingModel"] ?? "gpt-4o-mini";
|
|
|
|
[TempData]
|
|
public string? SuccessMessage { get; set; }
|
|
|
|
[TempData]
|
|
public string? ErrorMessage { get; set; }
|
|
|
|
[BindProperty]
|
|
public string? ParsingNotes { get; set; }
|
|
|
|
public async Task<IActionResult> OnGetAsync(long id)
|
|
{
|
|
Receipt = await _db.Receipts
|
|
.Include(r => r.Transaction)
|
|
.Include(r => r.LineItems)
|
|
.Include(r => r.ParseLogs.OrderByDescending(pl => pl.StartedAtUtc))
|
|
.FirstOrDefaultAsync(r => r.Id == id);
|
|
|
|
if (Receipt == null)
|
|
return NotFound();
|
|
|
|
LineItems = Receipt.LineItems?.OrderBy(li => li.LineNumber).ToList() ?? new();
|
|
ParseLogs = Receipt.ParseLogs?.OrderByDescending(pl => pl.StartedAtUtc).ToList() ?? new();
|
|
|
|
// Load saved parsing notes
|
|
ParsingNotes = Receipt.ParsingNotes;
|
|
|
|
// Get receipt URL for display - use handler parameter
|
|
ReceiptUrl = $"/ViewReceipt/{id}?handler=file";
|
|
|
|
// Get available parsers
|
|
AvailableParsers = _parsers.Select(p => new ParserOption
|
|
{
|
|
Name = p.GetType().Name.Replace("ReceiptParser", ""),
|
|
FullName = p.GetType().Name
|
|
}).ToList();
|
|
|
|
return Page();
|
|
}
|
|
|
|
public async Task<IActionResult> OnGetFileAsync(long id)
|
|
{
|
|
var receipt = await _receiptManager.GetReceiptAsync(id);
|
|
if (receipt == null)
|
|
return NotFound();
|
|
|
|
var filePath = _receiptManager.GetReceiptPhysicalPath(receipt);
|
|
if (!System.IO.File.Exists(filePath))
|
|
return NotFound("Receipt file not found on disk.");
|
|
|
|
var fileBytes = await System.IO.File.ReadAllBytesAsync(filePath);
|
|
|
|
// For PDFs, set content disposition to inline so they display in browser
|
|
if (receipt.ContentType == "application/pdf")
|
|
{
|
|
Response.Headers.Append("Content-Disposition", $"inline; filename=\"{receipt.FileName}\"");
|
|
return File(fileBytes, "application/pdf");
|
|
}
|
|
|
|
return File(fileBytes, receipt.ContentType);
|
|
}
|
|
|
|
public async Task<IActionResult> OnPostParseAsync(long id, string parser)
|
|
{
|
|
var selectedParser = _parsers.FirstOrDefault(p => p.GetType().Name == parser);
|
|
|
|
if (selectedParser == null)
|
|
{
|
|
ErrorMessage = "Parser not found.";
|
|
return RedirectToPage(new { id });
|
|
}
|
|
|
|
// Use the configured model from settings, pass user notes
|
|
var result = await selectedParser.ParseReceiptAsync(id, SelectedModel, ParsingNotes);
|
|
|
|
if (result.IsSuccess)
|
|
{
|
|
SuccessMessage = result.Message;
|
|
}
|
|
else
|
|
{
|
|
ErrorMessage = result.Message;
|
|
}
|
|
|
|
return RedirectToPage(new { id });
|
|
}
|
|
|
|
public class ParserOption
|
|
{
|
|
public string Name { get; set; } = "";
|
|
public string FullName { get; set; } = "";
|
|
}
|
|
}
|
|
} |