PSA/ee/docs/plans/xero-csv-export-progress.md
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

388 lines
16 KiB
Markdown

# Xero CSV Export/Import - Implementation Progress (Updated for 2025 Accounting Plan)
## Overview
This document tracks the implementation progress of the Xero CSV Export/Import feature. The goal is a CSV-based Xero integration (no OAuth required) that has **the same outcomes and invariants** as the automated accounting export system (batches, mappings, audit trail, and “already exported” behavior) — the only difference should be the manual import step.
**Branch:** `feature/xero-csv-export`
**Feature File:** `ee/docs/plans/features-xero-csv-export.json`
**Started:** 2024-12-16
**Last Updated:** 2025-12-18
---
## Progress Summary
| Category | Completed | Total | Progress |
|----------|-----------|-------|----------|
| Backend | 9 | 9 | 100% |
| Frontend | 8 | 8 | 100% |
| Data model / migrations | 2 | 2 | 100% |
| Documentation | 1 | 1 | 100% |
| Testing | 0 | 5 | 0% |
| **Overall** | **20** | **25** | **80%** |
---
## Implementation Log
### 2024-12-16 - Project Setup
- [x] Created feature branch `feature/xero-csv-export` from `release/0.15.0`
- [x] Set up development environment with unique ports (3007, 5434, 6381, 6434, 1236)
- [x] Created feature tracking files:
- `ee/docs/plans/features-xero-csv-export.json`
- `ee/docs/plans/xero-csv-export-progress.md` (this file)
- [x] Completed codebase exploration and planning phase
### 2025-12-18 - Plan refresh after QuickBooks CSV work
- [x] Updated plan to reflect the new unified Accounting Integrations setup + CSV mapping/export patterns.
- [x] Updated feature list to include missing "full integration" work: mappings UI/modules, batch immutability, client (contact) export/import, lock reset warnings, and parity with automated exports.
### 2025-12-18 - Core Implementation
**Backend:**
- [x] Created `XeroCsvAdapter` (`server/src/lib/adapters/accounting/xeroCsvAdapter.ts`)
- File-based delivery mode with Xero-compatible CSV format
- Fixed tracking categories: "Source System"/"AlgaPSA" and "External Invoice ID"/{invoice_id}
- Tax delegation support (exports as Draft for Xero tax calculation)
- [x] Registered adapter in `server/src/lib/adapters/accounting/registry.ts`
- [x] Created `XeroCsvTaxImportService` (`server/src/lib/services/xeroCsvTaxImportService.ts`)
- Parses Xero Invoice Details Report CSV format
- Matches invoices using tracking categories
- Preview and import functionality with audit trail
- [x] Created server actions (`server/src/lib/actions/integrations/xeroCsvActions.ts`)
- [x] Created API routes:
- `server/src/app/api/v1/accounting-exports/[batchId]/download/route.ts`
- `server/src/app/api/v1/accounting-exports/xero-csv/tax-import/route.ts`
**Frontend:**
- [x] Created `XeroCsvSettings` component (`server/src/components/settings/integrations/XeroCsvSettings.tsx`)
- [x] Updated `XeroIntegrationSettings` with CSV/OAuth mode toggle
- [x] Created `XeroCsvExportPanel` (`server/src/components/billing-dashboard/accounting/XeroCsvExportPanel.tsx`)
- [x] Created `XeroCsvTaxImportPanel` (`server/src/components/billing-dashboard/accounting/XeroCsvTaxImportPanel.tsx`)
- [x] Updated `AccountingExportsTab` for Xero CSV batch support
**Documentation:**
- [x] Created user guide (`ee/docs/guides/xero-csv-integration.md`)
- Setup instructions (tracking categories, mappings)
- Invoice export workflow
- Tax import workflow
- Client export/import instructions
- Lock reset and batch reversal documentation
- Troubleshooting guide
### 2025-12-18 - Integration with Unified Accounting Setup
After merging release/0.15.0, adapted Xero CSV integration to work with the new unified accounting integrations infrastructure:
**Infrastructure Integration:**
- [x] Updated `AccountingIntegrationsSetup.tsx` to add `xero_csv` as a fourth integration option
- [x] Created `XeroCsvIntegrationSettings.tsx` following the `CSVIntegrationSettings` pattern
- Merged settings from old `XeroCsvSettings.tsx` (date format, currency, setup acknowledgement)
- Added mapping manager integration
- Added workflow guide and navigation
- [x] Created `xeroCsvMappingModules.ts` for Xero CSV-specific mapping modules
- Clients, Items/Services, Tax Codes, Payment Terms
- Xero-specific terminology and identifiers
- [x] Created `XeroCsvMappingManager.tsx` component using the shared `AccountingMappingManager`
- [x] Updated CSV integration index exports
- [x] Removed old `XeroCsvSettings.tsx` (merged into `XeroCsvIntegrationSettings.tsx`)
### 2025-12-18 - Backend Completion
Completed all remaining backend tasks:
**Client Export/Import:**
- [x] Created `XeroCsvClientSyncService` (`server/src/lib/services/xeroCsvClientSyncService.ts`)
- Export Alga clients to Xero Contacts CSV format
- Import Xero Contacts CSV with preview and matching logic
- Persist external ID mappings per tenant + adapter type
- [x] Added client sync actions to `xeroCsvActions.ts`
- [x] Created client export API route (`/api/v1/accounting-exports/xero-csv/client-export/route.ts`)
- [x] Created client import API route (`/api/v1/accounting-exports/xero-csv/client-import/route.ts`)
**Batch Parity:**
- [x] Added `xero_csv` to `AccountingAdapterType` in `companySync.types.ts`
- [x] Updated `XeroCsvAdapter.deliver()` to create invoice mappings via `KnexInvoiceMappingRepository`
- [x] Added `xero_csv` to `shouldIncludePendingExternalDrafts()` in invoice selector
**Tax Blocking State:**
- [x] Verified existing tax blocking logic in `taxSourceActions.ts` handles `pending_external` state
- [x] Confirmed `XeroCsvTaxImportService` properly updates `tax_source` from `pending_external` to `external`
- [x] Invoice finalization is blocked until tax is imported (via `validateInvoiceFinalization`)
### 2025-12-18 - Data Model & Client Sync UI Completion
**Data Model / Migrations:**
- [x] Created `server/migrations/20251218010000_add_xero_csv_mapping_normalization.cjs`
- Normalizes `company``client` for xero_csv mappings
- Normalizes `tax_region``tax_code` for xero and xero_csv mappings
- Both up and down migrations implemented
- [x] External ID mapping persistence already handled by `XeroCsvClientSyncService`
- Persists client mappings per tenant + adapter type via `tenant_external_entity_mappings`
- Used for client import reconciliation
**Client Sync UI:**
- [x] Created `XeroCsvClientSyncPanel.tsx` component
- Export clients to Xero Contacts CSV with download
- Import clients from Xero CSV with preview table
- Match options: name, email, or Xero contact ID
- Create/update/skip actions per client
- Full preview → confirm → execute workflow
- [x] Integrated `XeroCsvClientSyncPanel` into `XeroCsvIntegrationSettings.tsx`
---
## Backend Tasks
### 1. Xero CSV Adapter (adapter-create)
**File:** `server/src/lib/adapters/accounting/xeroCsvAdapter.ts`
**Status:** DONE
- [x] Create adapter class implementing AccountingExportAdapter
- [x] Implement capabilities() with deliveryMode: 'file'
- [x] Implement transform() to generate Xero-compatible CSV
- [x] Include stable reconciliation identifiers (tracking categories)
- [x] Implement deliver() to prepare file artifact
### 2. Register Adapter (adapter-register)
**File:** `server/src/lib/adapters/accounting/registry.ts`
**Status:** DONE
- [x] Import XeroCsvAdapter
- [x] Add to createDefault() adapter list
### 3. CSV Mapping Modules (mapping-modules)
**File:** `server/src/components/integrations/csv/xeroCsvMappingModules.ts`
**Status:** DONE
- [x] Implement mapping modules for `adapterType: 'xero_csv'`
- [x] Support mappings for: Clients, Items/Services, Tax Codes, Payment Terms
- [x] Ensure terminology uses "Clients" (not "Customers") throughout UI/config
- [x] Default the mapping tab view to "Clients"
### 4. Client Export/Import (client-export-import)
**Files:**
- `server/src/lib/services/xeroCsvClientSyncService.ts`
- `server/src/app/api/v1/accounting-exports/xero-csv/client-export/route.ts`
- `server/src/app/api/v1/accounting-exports/xero-csv/client-import/route.ts`
**Status:** DONE
- [x] Export Alga Clients to Xero Contacts CSV (manual import to Xero)
- [x] Import Xero Contacts CSV back into Alga (match/update existing clients; optionally create new clients)
- [x] Persist external-id/linking mappings for clients per tenant + adapter type
### 5. Tax Import Service (tax-import-service)
**File:** `server/src/lib/services/xeroCsvTaxImportService.ts`
**Status:** DONE
- [x] Parse Xero Invoice Details Report CSV format
- [x] Match invoices back to Alga using tracking categories
- [x] Create previewTaxImport() method
- [x] Create importTaxFromReport() method
- [x] Record imports in `external_tax_imports` with consistent audit trail
### 6. Export/TX Import Actions (server-actions)
**File:** `server/src/lib/actions/integrations/xeroCsvActions.ts`
**Status:** DONE
- [x] Settings read/write for Xero CSV mode
- [x] Export: create/execute batch and return download artifact
- [x] Import: preview + execute tax import
- [x] Import: preview + execute client import
### 7. Xero CSV API Routes (api-routes)
**Files:** `server/src/app/api/v1/accounting-exports/...`
**Status:** DONE
- [x] Export download endpoint (`[batchId]/download/route.ts`)
- [x] Tax import endpoint (`xero-csv/tax-import/route.ts`)
- [x] Client export endpoint (`xero-csv/client-export/route.ts`)
- [x] Client import endpoint (`xero-csv/client-import/route.ts`)
### 8. Batch Parity / Immutability (batch-parity)
**Files:**
- `server/src/lib/adapters/accounting/xeroCsvAdapter.ts`
- `server/src/lib/services/accountingExportInvoiceSelector.ts`
- `server/src/lib/services/companySync/companySync.types.ts`
**Status:** DONE
- [x] Ensure exports create persisted batches with an audit trail (no in-memory-only exports)
- [x] Match OAuth export behavior for "already exported invoices" and date overlap handling
- [x] Added invoice mapping persistence in `XeroCsvAdapter.deliver()` to prevent re-export
- [x] Added `xero_csv` to `AccountingAdapterType`
### 9. External Tax Blocking State (tax-blocking-state)
**Files:**
- `server/src/lib/actions/taxSourceActions.ts`
- `server/src/lib/services/accountingExportInvoiceSelector.ts`
**Status:** DONE
- [x] If Xero is the tax source, treat invoices as blocked from finalization until tax is imported
- [x] Default export selection to include Draft invoices when invoices are awaiting external tax
- [x] `validateInvoiceFinalization()` blocks finalization for `pending_external` tax source
- [x] Added `xero_csv` to `shouldIncludePendingExternalDrafts()` for draft invoice inclusion
---
## Data model / migrations tasks
### A. Mapping type normalization (mapping-normalization)
**Files:** `server/migrations/20251218010000_add_xero_csv_mapping_normalization.cjs`
**Status:** DONE
- [x] Add/verify migrations to normalize mapping types (company → client, tax_region → tax_code) for `xero_csv`
- [x] Ensure the mapping resolver uses canonical mapping types across adapters
### B. External ID mapping persistence (external-id-mapping)
**Files:** `server/src/lib/services/xeroCsvClientSyncService.ts`
**Status:** DONE
- [x] Persist Xero external identifiers for clients and invoices per tenant + adapter type
- [x] Use these mappings for client import and tax import reconciliation
---
## Frontend Tasks
### 10. Xero CSV Integration Settings Panel (xero-csv-settings)
**File:** `server/src/components/settings/integrations/XeroCsvIntegrationSettings.tsx`
**Status:** DONE
- [x] Show instructions for manual import/export workflows (contacts + invoices + tax import)
- [x] Surface key defaults (invoice numbering/reference scheme; date formatting if needed)
- [x] Link users to mapping setup (must complete before exporting)
### 11. Accounting Integrations Setup Wiring (integrations-setup)
**File:** `server/src/components/settings/integrations/AccountingIntegrationsSetup.tsx`
**Status:** DONE
- [x] Keep Xero OAuth visible but disabled / "Coming soon" when in CSV mode
- [x] Add Xero CSV as a selectable integration option (fourth card)
- [x] Ensure only the selected integration's panes are displayed
### 12. Mapping Manager UI (mapping-manager)
**File:** `server/src/components/integrations/csv/XeroCsvMappingManager.tsx`
**Status:** DONE
- [x] Use shared mapping manager UI (standard tab control + primary color)
- [x] Default to the "Clients" tab on load
- [x] Ensure "Add Client Mapping" language (not "Customer")
### 13. Xero CSV Export UI (export-panel)
**File:** `server/src/components/billing-dashboard/accounting/XeroCsvExportPanel.tsx`
**Status:** DONE
- [x] Export dialog that matches OAuth export invariants (status defaults, overlap behavior, lock handling)
- [x] Provide "Reset export lock" / "Reverse batch" actions with warnings
### 14. Xero CSV Tax Import UI (tax-import-panel)
**File:** `server/src/components/billing-dashboard/accounting/XeroCsvTaxImportPanel.tsx`
**Status:** DONE
- [x] Upload + preview + execute flow with clear reconciliation identifiers
- [x] History + rollback UI (consistent with CSV tax import patterns)
### 15. Accounting Exports Tab Update (exports-tab-update)
**File:** `server/src/components/billing-dashboard/accounting/AccountingExportsTab.tsx`
**Status:** DONE
- [x] Ensure Xero CSV batches behave the same as other adapters (download, errors, lines, status)
- [x] Link to Xero CSV tax import + client export/import panels where appropriate
### 16. Client Export/Import UI (client-sync-ui)
**File:** `server/src/components/settings/integrations/XeroCsvClientSyncPanel.tsx`
**Status:** DONE
- [x] Export clients (contacts CSV) action + instructions
- [x] Import clients from Xero contacts CSV with preview + confirmation
- [x] Clear matching rules and "create vs update" outcomes
---
## Documentation Tasks
### 17. User Instructions (user-instructions)
**File:** `ee/docs/guides/xero-csv-integration.md`
**Status:** DONE
- [x] Xero contacts (clients) import/export guide
- [x] Invoice export workflow instructions
- [x] Tax import workflow instructions + rollback semantics
- [x] Troubleshooting section
---
## Testing Tasks
### 18. Adapter Tests (adapter-tests)
**File:** `server/src/test/unit/accounting/xeroCsvAdapter.spec.ts`
**Status:** Not Started
- [ ] CSV generation tests
- [ ] Reconciliation identifier inclusion tests
- [ ] Multi-invoice batch tests
### 19. Import Service Tests (import-tests)
**File:** `server/src/test/unit/accounting/xeroCsvTaxImportService.spec.ts`
**Status:** Not Started
- [ ] CSV parsing tests
- [ ] Invoice matching tests
- [ ] Tax application tests
### 20. Client Sync Tests (client-sync-tests)
**File:** `server/src/test/unit/accounting/xeroCsvClientSyncService.spec.ts`
**Status:** Not Started
- [ ] Client export CSV tests
- [ ] Client import matching/creation tests
### 21. Integration Tests (integration-tests)
**File:** `server/src/test/integration/accounting/xeroCsvExport.integration.test.ts`
**Status:** Not Started
- [ ] Full export workflow test
- [ ] Full import workflow test
- [ ] Error handling tests
### 22. Playwright Smoke Tests (ui-smoke-tests)
**File:** `server/src/test/playwright/accounting/xeroCsv.spec.ts`
**Status:** Not Started
- [ ] Integrations setup navigation + disabled OAuth cards
- [ ] Mapping manager default tab + save mapping flows
- [ ] Export + tax import smoke
---
## Notes & Decisions
### Key Implementation Notes
1. **Terminology**: Alga “Customers” are **Clients**; all UI/labels should use “Client”.
2. **Outcome Parity**: Xero CSV should use the same mapping resolver, batch persistence, and “already exported” handling as automated exports.
3. **Reconciliation Identifiers**: Prefer stable identifiers embedded in the CSV (InvoiceNumber + Reference containing Alga invoice ID) over relying on fragile matching rules.
4. **Immutability**: Exports are immutable; “re-export” is implemented via explicit lock reset with warnings (invoice-level and batch-level).
5. **External Tax**: When Xero is tax source, invoices should be blocked from finalization until taxes are imported (state is derived, not stored as a new field).
### Technical Debt / Future Improvements
- [ ] Consider adding batch progress tracking for large exports
- [ ] Consider adding retry logic for partial imports
- [ ] Consider caching Xero report column mappings per tenant (once the report format is finalized)
---
## Commits
| Date | Commit | Description |
|------|--------|-------------|
| 2024-12-16 | TBD | Initial feature setup and planning files |
---
*Last Updated: 2025-12-18 (Backend, Frontend, Data Model Complete - 80%; Only Testing Remains)*