Accounts Receivable Updates

Overview

This merge request brings several significant improvements to our invoice management application:

  • Dynamic Totals & Discounts:

    • Invoice totals are now computed dynamically based on each line item’s price and quantity, with any applicable discounts factored in. This replaces the old static total.
  • Advanced Invoice Status:

    • I've replaced the simple boolean "complete" flag with a multi-state system where invoices can be "Open", "Paid", or "Closed".
    • The UI now features a dropdown in the invoice detail view for updating the status, and the sidebar shows the count of invoices in the "Open" state for each client.
  • Code Cleanup & Test Separation:
    I've reorganized the project structure for better maintainability:

    • Components are now placed in src/components/.
    • Store logic is contained within src/store/, with its unit tests in src/store/tests/.
    • Utility functions reside in src/utils/, with corresponding tests in src/utils/tests/.
    • Component tests are separated into src/tests/.
    • End-to-end tests remain in the top-level e2e/ directory.
    • A global test setup file (src/setupTests.ts) is used for configuration (e.g., importing jest-dom).
  • Improved Test Coverage:
    Both unit tests and end-to-end tests have been expanded:

    • Unit Tests: Verify the correct calculation of totals, discount computations, status updates in the store, and component behavior.
    • E2E Tests: Validate critical user flows such as navigation, invoice status updates via the dropdown, and the invoice editing process.

Key Changes

  • Utils Update:
    The calculateInvoiceTotal function now computes the invoice total dynamically by summing subtotals for both projects and services, with discounts applied where relevant. For example:

    function calculateInvoiceTotal(invoice: Invoice): number {
      const computeSubtotal = (items: LineItem[]): number =>
        items.reduce((sum, item) => sum + item.price_cents * item.quantity, 0);
      return computeSubtotal(invoice.projects) + computeSubtotal(invoice.services);
    }
  • Store Enhancements:
    The Invoice interface now includes a state property with possible values "Open", "Paid", or "Closed". New actions (UPDATE_STATUS and EDIT_INVOICE) have been added to the reducer to support status updates and invoice editing.

  • Routing Updates:
    A new route /invoices/:id/edit has been added to allow users to edit invoices. This route renders the InvoiceAdd component in edit mode.

  • Testing Improvements:

    • Unit Tests: Validate store logic, utility functions, and component behaviors (including form pre-population and status updates).
    • End-to-End Tests: Ensure that user flows—such as navigating to the invoice edit page, updating status via the dropdown, and confirming updated data—work as expected.

How to Verify

  1. Run unit tests:
    npm test
  2. Run end-to-end tests:
    npm run test:e2e
  3. Manual Verification:
    • Start the development server with npm run dev.
    • Navigate to an invoice detail view and verify that the total is calculated dynamically and that the status dropdown works as intended.
    • Check the invoice edit functionality at /invoices/:id/edit to confirm the form is pre-populated and updates are saved.
    • Verify that the sidebar correctly groups invoices and shows the open invoice count per client.

This merge request not only enhances the core functionality of the invoice management application but also improves overall code organization and testing coverage, laying a strong foundation for future features.

Next Steps

  • Edit invoices
    • create InvoiceAdd component. The component would support an optional initialInvoice prop and an isEditing flag. When in edit mode, the form is pre-populated with existing invoice data and, on submission, dispatches an EDIT_INVOICE action.
  • Increase unit test coverage
  • Increase e2e coverage

Merge request reports

Loading