Files
integreat/docs/plans/2026-04-24-001-feat-complete-sales-summary-calculations-plan.md

9.4 KiB

title, type, status, date
title type status date
Complete Automatic Sales Summary Calculations and Ledger Posting feat completed 2026-04-24

Complete Automatic Sales Summary Calculations and Ledger Posting

What's Incomplete

  • Automatic Totals: Aggregate attributes (e.g., :sales-summary/total-card-payments) are not calculated/stored by the job.
  • Data Persistence: Automatic recalculations risk overwriting manual user adjustments.
  • Automation Gap: Ledger entries are currently imported from external Excel files rather than generated automatically from the summaries.
  • UI Polish: "Clientization" and HTMX context (client-id) TODOs remain in the admin interface.

Overview

...

This plan completes the implementation of automatic sales summary calculations and ensures they are correctly posted to the ledger. Currently, the sales-summaries-v2 job calculates detailed daily summaries, but it doesn't store aggregate totals, preserve manual adjustments, or trigger the creation of actual ledger entries. Additionally, the admin UI has several unresolved TODOs.


Problem Frame

The system currently aggregates raw sales data into a sales-summary entity, but the final step—creating balanced journal entries for the general ledger—is a manual process involving external Excel calculations and subsequent imports. This creates a dependency on external tools and increases the risk of data entry errors. The goal is to automate this pipeline entirely within the product.


Requirements Trace

  • R1. Calculate and store aggregate totals (e.g., :sales-summary/total-card-payments) on the sales-summary entity.
  • R2. Preserve user-made manual adjustments (:sales-summary-item/manual? true) during automatic recalculations.
  • R3. Aggregate detailed sales-summary-items into balanced journal-entry lines by account and location.
  • R4. Automate the posting of these aggregated totals to the ledger.
  • R5. Resolve UI TODOs in the Sales Summaries admin page, specifically regarding client-scoping ("clientize") and HTMX context (client-id).

Scope Boundaries

  • In-Scope:
    • Enhancements to the sales-summaries-v2 job.
    • Implementation of the summary-to-ledger aggregation and posting logic.
    • Cleanup of the Sales Summaries admin UI.
  • Out-of-Scope:
    • Changing the fundamental calculation logic for sales orders/refunds.
    • Creating new ledger accounts (assume existing account mapping is sufficient).
    • Changing the naming of refunds/returns (user requested to keep as is).

Context & Research

Relevant Code and Patterns

  • Jobs: src/clj/auto_ap/jobs/sales_summaries.clj contains the main calculation logic.
  • UI: src/clj/auto_ap/ssr/admin/sales_summaries.clj implements the admin interface.
  • Ledger Posting: src/clj/auto_ap/ledger.clj and iol_ion/src/iol_ion/tx/upsert_ledger.clj handle journal entry creation.
  • Reconciliation Pattern: reconcile-ledger in src/clj/auto_ap/ledger.clj shows how to find missing ledger entries and trigger their creation.

Institutional Learnings

  • No existing documented patterns for sales summary posting were found in docs/solutions/. This implementation will establish the pattern.

Key Technical Decisions

  • Detailed Summary \to Aggregated Ledger: The sales-summary will maintain granular detail (line items, specific fee types), but the ledger posting will aggregate these items by account and location to create balanced journal-entry lines.
  • Automatic Posting: Posting to the ledger will be integrated into the reconciliation process, similar to how invoices and transactions are handled in reconcile-ledger.
  • Location Handling: Since sales-summary-items don't have a location, a default location for the client will be used for ledger posting.

Open Questions

Resolved During Planning

  • Architectural Decision: Use a detailed summary that aggregates into the ledger.
  • Renaming: Keep "Refunds/Returns" as is.

Deferred to Implementation

  • Default Location Logic: Exactly how the "default location" for a client is retrieved or defined.

Implementation Units

  • U1. Enhance sales-summaries-v2 Job

Goal: Ensure the job stores aggregate totals and preserves manual adjustments.

Requirements: R1, R2

Dependencies: None

Files:

  • Modify: src/clj/auto_ap/jobs/sales_summaries.clj

Approach:

  • Update sales-summaries-v2 to calculate totals for attributes like :sales-summary/total-card-payments, :sales-summary/total-cash-payments, etc., based on the generated items.
  • Implement a merge strategy: when updating a summary, keep any items where :sales-summary-item/manual? is true, and only replace the automatically calculated items.

Test scenarios:

  • Happy path: Running the job for a client with sales and refunds results in a sales-summary with correct :sales-summary/total-* attributes.
  • Edge case: Running the job on a summary that already has a manual item ensures the manual item is not overwritten.

Verification:

  • Datomic query shows sales-summary entities have populated total attributes and preserved manual items.

  • U2. Implement Summary-to-Ledger Aggregation

Goal: Create a function to transform detailed summary items into balanced ledger lines.

Requirements: R3

Dependencies: U1

Files:

  • Create: src/clj/auto_ap/ledger/sales_summaries.clj (or add to src/clj/auto_ap/ledger.clj)
  • Test: test/clj/auto_ap/ledger_test.clj

Approach:

  • Create a function aggregate-summary-items that:
    1. Groups sales-summary-items by :ledger-mapped/account.
    2. Sums the :ledger-mapped/amount based on :ledger-mapped/ledger-side (debit vs credit).
    3. Assigns a location (default client location).
    4. Returns a list of journal-entry-line maps.

Test scenarios:

  • Happy path: A set of items with mixed accounts and sides aggregates into the correct number of ledger lines with summed amounts.
  • Edge case: Items with nil accounts are handled gracefully (e.g., mapped to an "Unknown" account or logged as error).

Verification:

  • Unit tests verify that a list of sales-summary-items is correctly transformed into journal-entry-lines.

  • U3. Implement Automatic Ledger Posting for Summaries

Goal: Ensure sales summaries trigger the creation of ledger entries.

Requirements: R4

Dependencies: U2

Files:

  • Modify: src/clj/auto_ap/ledger.clj
  • Modify: src/clj/auto_ap/jobs/sales_summaries.clj

Approach:

  • Implement a :upsert-sales-summary-ledger transaction or function that takes a sales-summary and uses the aggregation logic from U2 to post to the ledger.
  • Integrate this into the reconcile-ledger function in src/clj/auto_ap/ledger.clj to find summaries missing ledger entries and post them.

Test scenarios:

  • Integration: Running reconcile-ledger identifies a sales-summary missing a journal-entry and creates a balanced journal-entry for it.
  • Happy path: The created journal-entry has the correct total amount and matches the summary totals.

Verification:

  • A sales-summary entity is linked to a journal-entry via :journal-entry/original-entity.

  • U4. Resolve UI TODOs in Sales Summaries Admin

Goal: Fix client-scoping and HTMX context in the admin UI.

Requirements: R5

Dependencies: None

Files:

  • Modify: src/clj/auto_ap/ssr/admin/sales_summaries.clj

Approach:

  • Resolve "clientize" TODOs: Ensure the data pulled for the table and edit wizard is correctly scoped and transformed using client-specific context.
  • Fix HTMX client-id passing: Update the new-summary-item trigger to correctly pass the client-id via hx-vals from the form state.
  • Clean up any remaining schema TODOs in the SSR file.

Test scenarios:

  • Integration: Adding a new summary item in the UI correctly sends the client-id and the item is created for the correct client.
  • Happy path: The summary table displays correctly and "missing account" warnings appear only for items without a mapped account.

Verification:

  • Manual verification in the browser: New items are added correctly, and the UI is free of "missing account" red pills for mapped items.

System-Wide Impact

  • Interaction graph: The sales-summaries-v2 job now feeds into the ledger system via reconcile-ledger.
  • Error propagation: Failures in the aggregation logic will prevent the journal-entry from being created, which will be surfaced by reconcile-ledger as a missing entry.
  • State lifecycle risks: Ensuring that manual? items are not overwritten during automatic recalculation is critical to avoid losing user adjustments.
  • Integration coverage: Integration tests must cover the full flow: sales-orders \to sales-summary \to journal-entry.

Risks & Dependencies

Risk Mitigation
Overwriting manual adjustments Implement explicit merge logic based on the :sales-summary-item/manual? flag.
Unbalanced ledger entries Use a strict aggregation function that ensures debits = credits for every posted summary.
Missing location data Implement a robust fallback to a default client location.

Sources & References

  • Related code: src/clj/auto_ap/jobs/sales_summaries.clj
  • Related code: src/clj/auto_ap/ssr/admin/sales_summaries.clj
  • Related code: src/clj/auto_ap/ledger.clj
  • Related code: iol_ion/src/iol_ion/tx/upsert_ledger.clj