Skip to content

Invoice Creation from CSV Single-Row Import #444

Description

@Kingsman-99

Description

Accounts receivable staff often maintain invoice data in spreadsheets and want to quickly create a single StellarSplit invoice from a CSV row without the existing bulk-import flow (which requires many rows). This issue adds a "Import from CSV row" option to /invoice/new that parses a user-pasted CSV row (or a single-row file upload) against a documented column schema, maps fields to invoice form values, and pre-populates the form for the user to review and submit. Column mapping is configurable to support different spreadsheet layouts.

Technical Context

Create components/invoice/CSVRowImporter.tsx as a collapsible panel on app/invoice/new/page.tsx. The panel offers two input modes: (1) paste a CSV row with headers, (2) drag-and-drop a single-row CSV file. Parse input using papaparse with header: true. Define the expected schema in lib/csvInvoiceSchema.ts mapping CSV column names to InvoiceFormFields. Build a ColumnMappingModal that appears when the uploaded CSV has column names that do not match the expected schema; users drag-and-drop column names to map them. Validate parsed values with zod before calling form.reset(). Persist column mappings in localStorage so repeat imports from the same spreadsheet layout skip the mapping step. Support multi-recipient import via pipe-delimited recipients column in the format address1:percent1|address2:percent2.

Acceptance Criteria

  • Pasting a CSV row with recognised headers pre-populates the invoice form within one render cycle with no visible flash of empty state
  • When column names differ from the schema, the ColumnMappingModal appears and the user can map columns; the mapping is saved and reused on subsequent imports
  • The pipe-delimited recipients column correctly parses into multiple RecipientLine entries with the correct addresses and percentages
  • Validation errors (invalid G-address, negative amount, invalid date) are shown as inline errors in the form after import without blocking the modal close
  • Importing a CSV row does not overwrite any fields that the user has already manually filled in before importing; only empty fields are populated
  • All CI checks (npm test, npm run build, ESLint/TypeScript) pass and the branch has no merge conflicts

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions