InvoicePlane v1 could import historical invoices, invoice items, and payments from CSV — the backbone of migrating billing history into the app. v2 has no import code at all. The import/export epic #85 covers products (#140), catalogs (#139), clients (#141), and Excel support (#80), but invoice/item/payment import is listed nowhere.
Behavioral spec: v1 application/modules/import/models/Mdl_import.php and controllers/Import.php.
Specific
Add Filament ImportActions (with Importer classes) for three CSV types, matching v1's column contracts:
- invoices.csv —
user_email, client_name, invoice_date_created, invoice_date_due, invoice_number, invoice_terms (v1 Mdl_import.php:41-48)
- invoice_items.csv —
invoice_number, item_tax_rate, item_date_added, item_name, item_description, item_quantity, item_price (:49-57)
- payments.csv —
invoice_number, payment_method, payment_date, payment_amount, payment_note (:58-64)
Resolution rules (v1 parity):
user_email → existing user; row skipped with error if not found (:198-208).
client_name → existing Relation by name; auto-created if missing (:217-227).
invoice_number (items/payments) → existing invoice; row skipped if not found (:282-291, :360-367).
item_tax_rate (percent) → existing TaxRate by percent; auto-created if missing (:292-309).
payment_method (name) → existing payment method; auto-created if missing (:369-384).
Measurable
- Import buttons on the Invoices and Payments list pages (company panel).
- A 10-row valid invoices.csv creates exactly 10 invoices with correct dates, numbers, and terms; amounts recalculate after item import.
- Rows referencing unknown users/invoice numbers are skipped and reported per-row; no partial records.
- Auto-created relations/tax rates/payment methods are company-scoped.
Achievable
Importer classes at Modules/Invoices/Filament/Company/Imports/{InvoiceImporter,InvoiceItemImporter}.php and Modules/Payments/Filament/Company/Imports/PaymentImporter.php, wired via ImportAction::make()->importer(...) on the List pages. resolveRecord() implements the lookup/auto-create rules above. Requires publishing Filament's imports/failed_import_rows migrations (currently absent — only the exports table exists).
Relevant
Child of epic #85. Without historical invoices and payments, migrating users lose their books — client import alone (#141) is not a usable migration.
Time-Bound
One sprint after #141 lands (reuses its Importer conventions).
Arrange
- Company with 1 user (known email), 1 existing relation "Acme", a 20% tax rate, no payment methods.
- invoices.csv with 3 rows: one for "Acme", one for unknown client "Beta LLC", one with an unknown user_email.
- invoice_items.csv with rows for both invoice numbers, one item at tax rate 21 (not existing).
- payments.csv with one payment via method "Bank transfer" (not existing).
Act
- Run the three imports in order (invoices → items → payments) via the Filament ImportActions.
Assert
InvoicePlane v1 could import historical invoices, invoice items, and payments from CSV — the backbone of migrating billing history into the app. v2 has no import code at all. The import/export epic #85 covers products (#140), catalogs (#139), clients (#141), and Excel support (#80), but invoice/item/payment import is listed nowhere.
Behavioral spec: v1
application/modules/import/models/Mdl_import.phpandcontrollers/Import.php.Specific
Add Filament
ImportActions (with Importer classes) for three CSV types, matching v1's column contracts:user_email,client_name,invoice_date_created,invoice_date_due,invoice_number,invoice_terms(v1Mdl_import.php:41-48)invoice_number,item_tax_rate,item_date_added,item_name,item_description,item_quantity,item_price(:49-57)invoice_number,payment_method,payment_date,payment_amount,payment_note(:58-64)Resolution rules (v1 parity):
user_email→ existing user; row skipped with error if not found (:198-208).client_name→ existing Relation by name; auto-created if missing (:217-227).invoice_number(items/payments) → existing invoice; row skipped if not found (:282-291,:360-367).item_tax_rate(percent) → existing TaxRate by percent; auto-created if missing (:292-309).payment_method(name) → existing payment method; auto-created if missing (:369-384).Measurable
Achievable
Importer classes at
Modules/Invoices/Filament/Company/Imports/{InvoiceImporter,InvoiceItemImporter}.phpandModules/Payments/Filament/Company/Imports/PaymentImporter.php, wired viaImportAction::make()->importer(...)on the List pages.resolveRecord()implements the lookup/auto-create rules above. Requires publishing Filament's imports/failed_import_rows migrations (currently absent — only the exports table exists).Relevant
Child of epic #85. Without historical invoices and payments, migrating users lose their books — client import alone (#141) is not a usable migration.
Time-Bound
One sprint after #141 lands (reuses its Importer conventions).
Arrange
Act
Assert