Skip to main content

Regular Deposit Manager

Regular Deposit Manager

Component File: src/features/deposits/components/RegularDepositManager.tsx Route / navigation: Path /fund-accounting, Zustand accountingTool = regular-deposit (via Deposits sub-hub). See 00-ACCOUNTING-HUB.md. Access Level: Parent Org and Fund Users with accounting permissions (position-based) Last Updated: April 13, 2026

Overview

The Regular Deposit Manager allows users to manually record deposits that don't involve check scanning (cash, wire transfers, ACH, online payments, etc.). It provides a form-based interface for entering deposit details including payer information, amount, category, and bank information. Multiple line items batch into one deposit slip; when several funds are included and a parent org exists, the batch is tranched (one deposits row on the parent, per-fund GL credits with fundId). See 08-CHECK-DEPOSIT-MANAGER.md for the same pattern on check deposits.

Canonical workflow: Add to batch → batch review (draft batch)

The preferred user flow matches check deposits and the reimbursements / Add Expense intake pattern: stage line items into a working batch, review, then post.

1. Entry (form step) — User fills one line (payer, amount, account, purpose, etc.). Primary action: Add to batch (deposits.regular.addToBatch). This appends the line to the in-progress batch and navigates to the batch review screen (implementation: React state step switches from 'form' to 'complete'). 2. Batch review (“draft” batch) — The Review deposits / Complete step is the working batch: edit, delete, selective submit, totals, and final Submit to the ledger. Items persist in localStorage (alignmint-deposit-batch-{entityId}) until submitted or cleared — same persistence family as alignmint-check-batch-* and alignmint-reimbursement-batch-* (see 09-RECONCILIATION-MANAGER.md draft purge list).

Nomenclature: Call this the batch or draft batch in UX copy when distinguishing from posted deposits; the UI step title remains Review deposits / complete step. This parallels Check DepositComplete step and Reimbursements → Submit tab Complete step (staged receipts before submit). Server-backed Drafts in Reimbursements are a separate concept (saved expenses rows); the parallel is “stage → review batch → commit,” not the same storage layer.

Recent Fixes

Deposit edit re-entry safety + rollback cleanup (Apr 13, 2026)

  • Edit prefill fidelity: editDepositId prefill now restores line-level accounting context from deposit_items + linked donations: effective fund, saved revenue account (with default fallback only when needed), purpose, taxability, DAF flags/sponsor, and payment-method-derived intake method.
  • Duplicate guard on edit: Re-entry submit excludes donation IDs from the source batch so staff can correct and repost without being blocked by the very rows they are replacing.
  • Source batch lifecycle: After successful re-entry submit, the original pending draft batch is archived (deleteDeposit(..., { skipJournalEntryCleanup: true })) so it does not remain as an extra pending batch.
  • Failure rollback: Submit now performs compensating cleanup when partial steps succeed then fail (void created JE when present, archive created deposit, or soft-void created donations when no deposit row exists yet).
  • Finalize boundary: Rollback cleanup is now limited to pre-finalizeDeposit failures; once a batch is finalized, later non-critical errors do not unwind the posted deposit.

Donation-level void for posted regular deposits (Apr 12, 2026)

  • Standalone posted deposit: If a posted regular deposit has exactly one active deposit_item, the linked donation is now treated like a direct donation entry. Staff can void it from donation-context surfaces without having to void the whole deposit batch.
  • Future-safe partial void: New regular deposits now persist per-item posting context on deposit_items (revenue_account_id, purpose_id, fund_id) plus lifecycle state (status, voided_*). That allows donation-level void to create an additive reversing JE for just one donation amount while preserving both JE and deposit-item audit trail.
  • Historical regular deposits: Older multi-item regular deposits that do not have stored posting context remain whole-batch only for safe accounting. The app now returns an explicit \"ambiguous historical regular deposit\" error instead of guessing.
  • Audit trail: Deposit items are now soft-voided (status='voided') rather than deleted, and active totals/counts ignore voided items.

Calculator-style amount entry (Apr 9, 2026)

  • Regular Deposit is included in the live fund-accounting calculator-input rollout.
  • The form Amount field now accepts basic arithmetic expressions such as 152.48+157.82, subtraction, multiplication, and division; the evaluated number is committed on blur or Enter.
  • Invalid expressions keep the last committed numeric amount instead of silently converting the field to 0.

Donation Revenue default for deposit intake (Apr 8, 2026)

  • Rule: Same as Check Deposit — each fund in the batch needs an effective donations_revenue default before Add to batch (when the fund is selected) and before Submit. Funds can use an explicit override or inherit the parent organization’s mapping. There is no silent use of the first revenue account in the chart.
  • Client: getDefaultAccountId + resolveDonationRevenueCategoryId() (regularDepositTaxDefaults.ts) map the effective UUID to a revenue line on the fund’s chart only when types align.
  • Multi-fund: Submit loads fetchAccounts for every fund in the batch to build a merged account map for JE / memorized aggregation. Submit validates effective defaults per fund and requires categoryAccountId on every line.
  • Draft batch UI: Account names for lines from other funds use parallel useQueries over fetchAccounts so the review list is not limited to the current form fund’s chart.
  • Edit from Deposit History: Prefill preserves saved per-line revenue account/fund/purpose/DAF/tax state first, then falls back to effective defaults only where the saved account is unavailable.
  • Remediation: Alerts + Open Account DefaultsnavigateTo('administration','chart-of-accounts',{ accountDefaultsTab:'defaults' }); submit disabled while default queries are pending or any selected fund is missing a resolvable mapping.
  • IFM: See migration 20260408120000_ifm_donations_revenue_default_4000_02.sql (Donation Revenue → 4000.02 when present).

createDonation() DAF column alignment (Apr 2026)

  • Batch submit already maps DAF lines with donationPaymentMethodFromDepositRow() (isDafGiftpayment_method = 'daf').
  • The shared client createDonation() in src/lib/db/donations.ts additionally normalizes payment_method, is_daf_gift, and DAF sponsor fields on insert for all callers.
  • New enforcement (Jun 2026): non-interfund DAF donations now require daf_sponsor_id at both app and schema layers (chk_donations_daf_sponsor_required, migration 20260615120000_enforce_daf_sponsor_and_memtx_deposit_requirements.sql).
  • Legacy sponsorless DAF gifts are backfilled to Unknown DAF (Needs Review) per organization so existing reporting remains traceable.

DAF sponsor “sticks” across lines and sessions (Apr 2, 2026)

  • Problem: Users (e.g. repeated DAF gifts in one sitting) had to re-select the DAF toggle and sponsor on every new deposit line; it looked like the app was not saving DAF even though posted donations were correct.
  • Root cause: After Add to batch, the empty form reset copied the default revenue account but always cleared isDafGift / dafSponsorId / dafSponsorName. The same fields were cleared again after a successful Submit when opening a fresh line.
  • Behavior now:
  • After adding a line, the next empty form reuses DAF fields from the line just added (user can still turn DAF off or change sponsor).
  • After submit, the next empty form reuses DAF from the last submitted selected line.
  • When a draft batch is restored from localStorage, the empty entry form reuses DAF from the last row in the restored batch so the next line matches the batch pattern.
  • Files: RegularDepositManager.tsx

Standardized donor duplicate guard (Apr 2, 2026)

  • Regular Deposit now uses shared guard logic from src/lib/donationEntryGuards.ts (runDonationDuplicateGuard + shared block message builder).
  • High-confidence duplicates (same org + amount + date + payer, and check/reference when present, matched through existing deposit_items) are hard-blocked before posting.
  • This guard logic is shared with Check Deposit and Manual Add Donation (Record mode) for consistent behavior.
  • Files: RegularDepositManager.tsx, donationEntryGuards.ts

Add to batch → draft batch navigation + copy (Mar 30, 2026)

  • Behavior: After a valid Add to batch, handleAddDeposit calls setStep('complete') so the user lands on the Draft batch review step immediately (same intent as check deposit / reimbursement Complete staging).
  • UX: Entry card uses Add a deposit line + short helper description; draft step title Draft batch + description; page subtitle switches while on the draft step; banner/outline actions use Open draft batch / Draft batch (N); footer uses Back to add lines.
  • i18n: New keys under deposits.regular.* in all 7 locales (entryCardTitle, entryCardDescription, draftBatchTitle, draftBatchDescription, headerSubtitleDraft, goToDraftBatch, goToDraftBatchCount, backToAddLines).
  • Files: RegularDepositManager.tsx, src/i18n/locales/*/deposits.json

Tranched multi-fund regular deposit (Mar 27, 2026)

  • Behavior: One createDeposit + one compound createJournalEntry per submit; revenue credits grouped by fund + revenue account with explicit fundId on each JE line; header org = parent when multi-fund + parent exists.
  • Files: RegularDepositManager.tsx, get_deposit_history_page migration 20260327200000_deposit_history_tranched_visibility.sql.

Deposit-Linked JE Void Standardization (March 8, 2026)

  • Deposit-linked journal entries are no longer treated as standalone JE voids from some screens and deposit-batch voids from others.
  • Shared JE UI surfaces now route deposit-linked entry voids through voidJournalEntryWithDependencies() -> voidDepositBatch().
  • voidDepositBatch() now requires a reason and fails fast if it cannot resolve the linked JE, instead of silently continuing with a partial accounting rollback.
  • Deposit History also requires a reason when voiding a posted deposit batch.

Deposit Manager Audit — Keyboard Navigation, Label Consistency, Playbook Compliance (Mar 6, 2026)

1. AccountSearch component uses a Popover with a Button trigger. Tab lands on the button but the popover doesn't open — user must click or press Enter/Space, then manually focus the search input inside. 2. i18n keys deposits.regular.category and deposits.table.category both resolved to "Category" in English, while CheckDepositManager review cards and view dialog used hardcoded "Account".

  • Problem: Maribeth Carlton reported two issues: (1) Tab key cannot reach the Account (category) field — user must click to open, breaking form keyboard flow; (2) Label inconsistency — field labeled "Category" in some places, "Account" in others.
  • Root Cause:
  • Solution:
  • P0 (Keyboard): Added onFocus handler to AccountSearch trigger button to auto-open the popover on tab-focus. Added useEffect to auto-focus the CommandInput search field when popover opens, enabling immediate type-to-filter.
  • P1 (Labels): Renamed all category i18n values from "Category" to "Account" across all 6 locales (en/es/fr/de/zh/th). Updated CheckDepositManager review card and view dialog to use t('deposits.regular.category') instead of hardcoded "Account".
  • P2 (§28): Replaced <Input type="number"> with <CurrencyInput> on CheckDepositManager amount field.
  • P2 (§16 stat tiles): Removed Banknote/DollarSign icons from CheckDepositManager stat tiles (violates "NO icons in stat tiles" rule). Added useCountUp animations. Replaced hardcoded $ + .toFixed(2) with formatCurrency(). Matched RegularDepositManager pt-6 text-center layout.
  • P2 (formatCurrency): Replaced all remaining hardcoded $ amounts in CheckDepositManager (capture summary, review cards, view dialog) with formatCurrency().
  • Files Modified: AccountSearch.tsx, CheckDepositManager.tsx, 6 locale deposits.json files
  • No database changes

Selective Batch Submission (Mar 1, 2026)

  • Feature: Users can now choose which items from a batch to include in a deposit, keeping the rest for a future deposit.
  • Problem: Previously, all items in a batch were submitted together — there was no way to deposit a subset and retain the rest.
  • Solution:
  • Added selected field to DepositData interface (defaults to true)
  • Review step now shows per-item checkboxes and a Select All/Deselect All toggle
  • Summary stats show "Selected / Total" count and "Selected Amount" vs "Batch Total"
  • Submit button dynamically shows "Submit N of M" when a subset is selected
  • Submit handler filters to selected items only; unselected items remain in the batch and persist in localStorage
  • After submission, remaining items stay in the batch with an info toast ("N items remain in batch")
  • No database changes required — purely frontend logic
  • Files Modified: RegularDepositManager.tsx

Deposit Account Resolution & Date Fix (Feb 25, 2026)

  • Problem: Both RegularDepositManager and CheckDepositManager hardcoded '1000' for cash account lookup instead of using the getDefaultAccountIds RPC. QuickEntryDrawer used .toISOString().split('T')[0] for date initialization, violating §22.
  • Root Cause: Legacy code predating the organization_account_defaults system and the toLocalDateString() utility.
  • Solution:
  • Replaced accounts.find(a => a.code === '1000') with getDefaultAccountIds(orgId, ['default_checking']) in both deposit managers (JE creation + memorized transaction paths)
  • Replaced new Date().toISOString().split('T')[0] with toLocalDateString(new Date()) in QuickEntryDrawer (init + reset)
  • Files Modified: RegularDepositManager.tsx, CheckDepositManager.tsx, QuickEntryDrawer.tsx
  • Data Fix: Deleted erroneous void JE-2026-225 (2 lines) for Grapevine Ministries — a $150 Jan 2 deposit was incorrectly voided on Feb 10 as "double entry", restoring $150 to Income Statement

Deposit Void/Delete Bug Fix (Feb 14, 2026)

1. voidDepositBatch() lost donation links mid-loop because softDeleteDonation() cleared deposit_items.donation_id before all items were processed 2. voidDepositBatch() JE lookup failed for 31/32 deposits — deposit_id column on JE lines was only populated starting 2/13/2026 3. deleteDeposit() hard-deleted without cleaning up donations or JE lines 4. deleteDepositItem() orphaned linked donations 5. JournalEntryManager deposit cleanup used wrong query pattern 6. No void/delete UI existed in Deposit History 7. softDeleteDonation() prematurely cleared deposit_items.donation_id audit trail

  • Problem: Deleting or voiding a deposit did not clean up linked donations or journal entries, leaving orphaned active donations that inflated donor balances. Reported by Maribeth Carlton for Philip Laube (Deeper Walk).
  • Root Cause (7 bugs):
  • Solution:
  • softDeleteDonation() no longer clears deposit_items.donation_id (preserves audit trail)
  • voidDepositBatch() snapshots all donation IDs before mutations + adds fallback JE lookup by org+date+description+amount
  • deleteDeposit() now soft-deletes linked donations and voids linked JE before hard-deleting
  • deleteDepositItem() now soft-deletes its linked donation before removing the item
  • Added Void/Delete actions to Deposit History UI (gated behind canWriteAccounting)
  • JournalEntryManager deposit cleanup uses ilike pattern + deposit table fallback
  • DB migration backfilled deposit_id on 42 JE lines across 18 deposits
  • Data repair: voided orphaned Philip Laube donation, corrected donor stats
  • Files Modified: src/lib/db/deposits.ts, src/lib/db/donations.ts, src/features/deposits/components/DepositHistory.tsx, src/features/accounting/components/JournalEntryManager.tsx

Journal Entry Account ID Fix (Dec 31, 2025)

  • Problem: Journal entries were being created with hardcoded string account IDs ('acc-1000', 'acc-4000') instead of actual UUID account IDs from the Chart of Accounts, causing database foreign key constraint failures
  • Root Cause:
  • Component imported fetchAccounts but never called it
  • Category value stored as full string (e.g., "4000 - Donations") was being concatenated into invalid IDs like "acc-4000 - Donations"
  • Solution:
  • Added React Query to fetch accounts from Chart of Accounts
  • Look up Cash account (1000) and Revenue account by code
  • Parse category code from the full category string before lookup
  • Added error handling with toast notifications if accounts not found
  • Technical Details:
  const cashAccount = accounts.find((a: Account) => a.code === '1000');
  const categoryCode = entityDeposits[0].category?.split(' - ')[0] || '4000';
  const revenueAccount = accounts.find((a: Account) => a.code === categoryCode);
  • Impact: Journal entries now correctly reference actual account UUIDs, ensuring proper ledger entry creation

Parent Org Filtering (Dec 31, 2025)

  • Problem: Users could select the parent org organization when adding deposits, but deposits should be submitted at the fund level
  • Solution: Added depositEligibleEntities filter to exclude parent_org type organizations from the nonprofit dropdown
  • Behavior:
  • In multi-org setups, the parent org is hidden from the dropdown
  • In single-org setups (standalone nonprofit), the org is shown regardless of type
  • The 'all' pseudo-entity is always excluded
  • Technical: Uses useMemo to filter entities by type, with special handling for single-org scenarios

Purpose Dropdown Added (Dec 30, 2025)

  • Feature: Added Purpose dropdown to deposit form
  • Problem: Regular deposits were using hardcoded Income Categories but missing the Purpose field, which is required for proper donation categorization (e.g., "2026 Africa Trip", "General Fund")
  • Solution:
  • Added purpose field to DepositData interface
  • Added Purpose dropdown that fetches from purposes table based on selected nonprofit
  • Purpose is now required for deposit submission
  • Donation records created from deposits now use the selected purpose
  • Technical Details:
  • Uses fetchPurposes(entityId, false) from lib/db.ts
  • Purpose dropdown is disabled until nonprofit is selected
  • Changing nonprofit clears the purpose selection
  • Purpose displayed in review step before submission
  • Impact: Donations created from regular deposits now have proper purpose categorization for reporting

Add New Donor Integration (Dec 22, 2025)

  • Feature: Added "Add New Donor" button next to Payer Name field
  • Use Case: When recording a deposit from a new donor (e.g., someone who sent a check), users can now create the donor record with full details (name, email, phone, address) without leaving the deposit form
  • Implementation:
  • Uses existing AddDonorDialog component from components/shared/
  • Button appears next to "Payer Name" label
  • After donor is created, their name auto-populates the Payer Name field
  • Donor is created in the selected nonprofit's CRM
  • Benefits:
  • Capture donor address for thank-you letters and tax receipts
  • No need to navigate away and lose deposit form data
  • Consistent donor data entry across the application

Shared donor picker standard (Apr 2026)

  • Current implementation: Payer lookup now uses shared `DonorSearch` (src/components/shared/DonorSearch.tsx) instead of a local Popover + Command implementation.
  • Backend: DonorSearch uses searchDonorsAndProspects() (RPC-backed search_donors_and_prospects_autocomplete) and stays fund-scoped.
  • Shared autocomplete config: 2-character minimum, 150ms debounce, 30s React Query stale cache via autocompleteSearchConfig.ts.
  • Result: Regular Deposit now matches donor picker UX/behavior used across shared accounting and CRM surfaces.

Date Timezone Fix & Manual Input (Dec 22, 2025)

  • Problem: Dates entered on deposit form showed as one day earlier on review page due to UTC timezone conversion
  • Root Cause: Using toISOString().split('T')[0] converts dates to UTC, shifting dates backward for users in timezones behind UTC (e.g., CST/CDT)
  • Solution:
  • Added toLocalDateString() utility to dateUtils.ts that preserves local timezone
  • Updated all date conversions in RegularDepositManager to use new utility
  • Additional Enhancement: DatePicker now supports manual text input (MM/DD/YYYY format) in addition to calendar selection
  • Impact: No database changes, no impact on existing stored data

Searchable Donor Dropdown

  • Problem: Plain text input for payer name led to typos, inconsistent naming, and end-of-year reporting errors
  • Solution: Added shared searchable donor/prospect picker (DonorSearch) for payer entry
  • Behavior:
  • As user types 2+ characters, matching donors/prospects appear in dropdown
  • User can select from list OR continue typing a custom name
  • Supports non-donor payers (grants, corporate sponsors, etc.)
  • Uses the same shared picker pattern as Donations and Check Deposit
  • Technical: Shared DonorSearch wraps React Query + RPC autocomplete; field linkage is stored as donorId / donorSource

Dropdown Styling Fix (Feb 2, 2026)

  • Problem: Donor search dropdown was transparent in dark mode, making it difficult to read
  • Solution: Changed dropdown container from bg-popover to bg-card border-border for solid background
  • Files Modified:
  • RegularDepositManager.tsx - Payer name and soft credit donor dropdowns
  • CheckDepositManager.tsx - Soft credit donor dropdown
  • DonationsManager.tsx - All donor search dropdowns (3 instances)
  • Pattern: Use bg-card border border-border for dropdown containers, Command className="bg-transparent" for the Command component

Batch Persistence (localStorage)

  • Problem: Deposits entered in a batch were lost if user navigated away before submitting
  • Solution: Added localStorage persistence for deposit batches
  • Behavior:
  • Batch is automatically saved to localStorage as deposits are added
  • On return to page, saved batch is restored with notification
  • Batches expire after 24 hours
  • "Clear" button allows users to discard saved batch
  • Batch is cleared from localStorage after successful submission
  • Technical: Uses localStorage with entity-specific keys (alignmint-deposit-batch-{entityId})

UI Features

Main Features

  • Two-step process (aligned with check deposit + reimbursement batch flows):
  • Form step — Enter one deposit line; Add to batch adds it and moves focus to the batch review step (same idea as finishing a check line and landing on Complete, or finishing a receipt review and landing on the Submit tab Complete step).
  • Complete step — Working draft batch: list, per-line selection for partial submit, edit/delete, totals, Back to form to add another line, Submit to post selected lines to the ledger.
  • Deposit Form:
  • Payer name with searchable donor dropdown (matches existing donors)
  • Reference number
  • Amount
  • Date
  • Income category selector
  • Nonprofit selector (for parent org users)
  • Purpose selector (fetches from purposes table based on selected nonprofit)
  • Memo/notes
  • Non-taxable checkbox (marks donation as not tax-deductible)
  • Batch Management:
  • Add multiple deposits
  • Review deposit list
  • Edit/delete deposits
  • Total amount display
  • Selective submission — per-item checkboxes to choose which deposits to include
  • Select All / Deselect All toggle
  • Submit button shows "Submit N of M" when a subset is selected
  • Unselected items remain in the batch after submission
  • Revenue account (UI): AccountSearch over the fund’s chart (revenue accounts). The default selection comes only from the fund’s org-owned donations_revenue mapping (see Recent Fixes → Apr 7, 2026). The numeric list below is illustrative of common IFM-style codes, not a hard-coded picker.
  • 4000 - Donations
  • 4100 - Earned Income
  • 4200 - Cash Pledge Collections
  • 4300 - Grants
  • 4400 - Government Grants
  • 4500 - Investment Income
  • 4600 - Other Income
  • Back to Accounting Hub button

Form step (entry)

Regular Deposit Entry

┌─────────────────────────────────────────┐
│ Deposit Information                     │
├─────────────────────────────────────────┤
│                                         │
│ Payer Name *          [+ Add New Donor] │
│ [John Smith                         ]   │
│  ├─ John Smith (john@example.com)       │
│  ┐─ John Smithson (jsmith@org.com)      │
│                                         │
│ Reference Number                        │
│ [TXN-12345                          ]   │
│                                         │
│ Amount *                                │
│ [500.00                             ]   │
│                                         │
│ Date                                    │
│ [2025-10-20                         ]   │
│                                         │
│ Income Category *                       │
│ [4000 - Donations                   ▼]  │
│                                         │
│ Nonprofit * (Parent Org Only)           │
│ [Awakenings                         ▼]  │
│                                         │
│ Purpose *                               │
│ [2026 Africa Trip                   ▼]  │
│                                         │
│ Memo                                    │
│ [Monthly donation                   ]   │
│ [                                   ]   │
│                                         │
│ [Add to Batch]                          │
┐─────────────────────────────────────────┘

Current Batch (2 deposits, $1,250.00 total)

Complete step (batch review / draft batch)

Review Deposits

Payer Name      | Ref #      | Amount   | Date       | Category   | Purpose          | Nonprofit   | Actions
----------------|------------|----------|------------|------------|------------------|-------------|--------
John Smith      | TXN-12345  | $500.00  | 2025-10-20 | Donations  | 2026 Africa Trip | Awakenings  | [Edit] [Delete]
Jane Doe        | TXN-12346  | $750.00  | 2025-10-20 | Grants     | General Fund     | Bloom       | [Edit] [Delete]

Total: $1,250.00

[Back to Form]  [Submit Deposits]

Success Screen

┌─────────────────────────────────────────┐
│              ✓                          │
│                                         │
│   Deposits Submitted Successfully!      │
│                                         │
│   2 deposits totaling $1,250.00         │
│   have been recorded.                   │
│                                         │
│   Ledger entries have been created.     │
│                                         │
│   [Record More Deposits] [View Ledger]  │
┐─────────────────────────────────────────┘

Data Requirements

Deposit Data

  • id (uuid) - Deposit identifier
  • payer_name (string) - Who paid
  • reference_number (string, nullable) - Transaction reference
  • amount (decimal) - Deposit amount
  • date (date) - Deposit date
  • category (string) - Income category code
  • category_name (string) - Category display name
  • memo (string, nullable) - Notes
  • bank_name (string, nullable) - Bank name
  • entity_id (uuid) - Nonprofit organization
  • created_by (uuid) - User who recorded
  • created_at (timestamp)

Batch Submission

  • deposits (array) - Array of deposit data
  • total_amount (decimal) - Sum of all deposits
  • submission_date (date) - When submitted

Request/Response Schemas

interface DepositData {
  id: string;
  payer_name: string;
  reference_number?: string;
  amount: number;
  date: string;
  category: string;
  category_name: string;
  purpose: string;
  memo?: string;
  bank_name?: string;
  entity_id: string;
  created_by: string;
  created_at: string;
}

interface DepositBatch {
  deposits: DepositData[];
  total_amount: number;
  submission_date: string;
}

Authentication & Authorization

Required Permissions

  • deposits:create - Record deposits
  • deposits:read - View deposits

Role-Based Access

  • Parent Org (`parent_org`): Record deposits for any nonprofit
  • Fund User (`fund_user`): Record deposits for their nonprofit only
  • Accounting positions: Full access within assigned org(s)
  • Donor/Volunteer: No access

Business Logic & Validations

Frontend Validations

  • Payer name required
  • Amount required and > 0
  • Date required
  • Revenue account (categoryAccountId) required — tied to org-owned donations_revenue + chart (see Recent Fixes → Apr 7, 2026)
  • Entity required (parent org)
  • Purpose required
  • DAF lines require a selected DAF sponsor
  • Amount format validation
  • Date not in future

Backend Validations (Rails)

  • Valid organization access
  • Valid category code
  • Valid date format
  • Amount positive
  • Duplicate detection
  • Valid entity assignment

Business Rules

  • Each deposit creates ledger entry
  • Debit: Cash/Bank Account
  • Credit: Income Category Account
  • Batch submission supports compensating rollback on partial-write failures before finalize; finalized batches remain posted
  • Reference numbers tracked for reconciliation
  • Deposits linked to entity for reporting
  • Audit trail for all deposits

State Management

Local State

  • step - 'form' or 'complete'
  • deposits - Array of deposits in batch (persisted to localStorage)
  • currentDeposit - Form data for current deposit
  • currentDeposit.donorId / currentDeposit.donorSource - Donor linkage metadata from shared picker

Persisted State (localStorage)

  • alignmint-deposit-batch-{entityId} - Saved deposit batch with timestamp
  • Auto-expires after 24 hours
  • Cleared on successful submission or manual clear

Global State (AppContext)

  • selectedEntity - Current organization

Dependencies

Internal Dependencies

  • AppContext - Global state
  • INCOME_CATEGORIES - Category list
  • DonorSearch - Shared payer donor/prospect lookup component
  • searchDonorsAndProspects - RPC-backed donor/prospect autocomplete
  • fetchPurposes - Fetches purposes for selected nonprofit
  • UI components (Card, Button, Input, Select, etc.)

External Libraries

  • lucide-react - Icons
  • sonner - Toast notifications
  • @tanstack/react-query - Data fetching and caching for donors

Error Handling

Error Scenarios

1. Missing Required Fields: Show error "Please fill in all required fields" 2. Invalid Amount: Show error "Amount must be greater than 0" 3. Empty Batch: Show error "Please add at least one deposit" 4. Submission Failed: Show toast "Failed to submit deposits" 5. Network Error: Show toast "Connection error, please try again"

Loading States

  • Add to Batch: Button loading state
  • Submit: Button loading state with progress
  • Success: Fade transition to success screen

Mock Data to Remove

  • RegularDepositManager.tsx - INCOME_CATEGORIES (move to API)
  • Move interfaces to src/types/deposits.ts

Migration Notes

Phase 1: Data Layer Integration

1. Create/expand Supabase helpers for regular deposit submission and category loading 2. Create src/types/deposits.ts 3. Implement submission endpoint 4. Test batch processing

Phase 2: Ledger Integration

1. Create ledger entries on submission 2. Test double-entry bookkeeping 3. Verify account balances 4. Add reconciliation support

Phase 3: Advanced Features

1. Add deposit templates 2. Implement recurring deposits 3. Add bulk import from CSV 4. Implement approval workflow

Related Documentation

Additional Notes

Use Cases

1. Cash Deposits: Recording cash donations 2. Wire Transfers: Recording wire payments 3. ACH Deposits: Recording ACH transactions 4. Online Payments: Recording Stripe/PayPal 5. Grant Payments: Recording grant disbursements

Ledger Entries Created

For each deposit:

Debit:  Cash - Operating Account    $500.00
Credit: 4000 - Donations             $500.00

Batch Processing

  • Multiple deposits submitted together
  • Single API call for efficiency
  • Compensating rollback if any step fails mid-submit
  • Email confirmation sent

Reconciliation

  • Reference numbers aid reconciliation
  • Deposits appear in bank reconciliation
  • Can match to bank statement lines
  • Unmatched deposits flagged

Reporting

  • Deposits by category
  • Deposits by entity
  • Deposits by date range
  • Deposits by user
  • Deposit trends

Best Practices

  • Enter deposits daily
  • Use consistent reference numbers
  • Include detailed memos
  • Verify amounts before submission
  • Reconcile regularly
  • Review for duplicates

Synced from IFMmvp-Frontend documentation: pages/accounting/10-REGULAR-DEPOSIT-MANAGER.md

Ready to Get Started?

See how Alignmint can simplify your nonprofit's operations. Schedule a free demo with our team and we'll walk you through everything.

Questions? Email us at steven@getalignmint.org

Ready to get started?Start Plus Trial