Private
Public Access
1
0

Implement Phase 2: end-to-end import system

Complete the import flow from file upload through duplicate resolution
to transaction creation. Previously, ResolveDuplicatesAsync was a stub
that only incremented counters, FileWatcherService detected files but
didn't process them, and ImportsView.vue ignored the API response.

Backend:
- Add ParsedDataJson column to ImportBatch to persist parsed data
  between upload and confirm steps
- Rewrite ImportService.ResolveDuplicatesAsync to deserialize parsed
  transactions and create/merge/skip based on user decisions, with
  payee matching, fingerprinting, and account balance updates
- Add GetBatchesAsync for import history
- Complete FileWatcherService: wait for file ready, resolve account by
  filename, call UploadAsync, send SignalR notification, archive file
- Add GET /api/imports/batches endpoint

Frontend:
- Create imports API service (frontend/src/services/imports.ts)
- Add ImportBatch, DuplicateResolution types
- Rewrite ImportsView.vue with 3-step Vuetify stepper wizard:
  upload, review with duplicate handling, completion summary,
  plus import history table

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Catherine Renelle
2026-02-08 11:16:39 -05:00
parent 0b6ff8faf1
commit 2ace39c544
12 changed files with 1844 additions and 39 deletions
@@ -12,6 +12,7 @@ public class ImportBatchConfiguration : IEntityTypeConfiguration<ImportBatch>
builder.HasKey(b => b.Id);
builder.Property(b => b.FileName).HasMaxLength(500).IsRequired();
builder.Property(b => b.FileType).HasMaxLength(50).IsRequired();
builder.Property(b => b.ParsedDataJson).HasColumnType("text");
builder.HasOne(b => b.User)
.WithMany()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Purrse.Data.Migrations
{
/// <inheritdoc />
public partial class AddParsedDataToImportBatch : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ParsedDataJson",
table: "import_batches",
type: "text",
nullable: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ParsedDataJson",
table: "import_batches");
}
}
}
@@ -249,6 +249,9 @@ namespace Purrse.Data.Migrations
b.Property<int>("ImportedCount")
.HasColumnType("integer");
b.Property<string>("ParsedDataJson")
.HasColumnType("text");
b.Property<int>("SkippedCount")
.HasColumnType("integer");