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 Deposit → Complete 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:
editDepositIdprefill now restores line-level accounting context fromdeposit_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-
finalizeDepositfailures; 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 orEnter. - 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_revenuedefault 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
fetchAccountsfor every fund in the batch to build a merged account map for JE / memorized aggregation. Submit validates effective defaults per fund and requirescategoryAccountIdon every line. - Draft batch UI: Account names for lines from other funds use parallel
useQueriesoverfetchAccountsso 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 Defaults →
navigateTo('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()(isDafGift→payment_method = 'daf'). - The shared client
createDonation()insrc/lib/db/donations.tsadditionally normalizespayment_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_idat both app and schema layers (chk_donations_daf_sponsor_required, migration20260615120000_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,
handleAddDepositcallssetStep('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 compoundcreateJournalEntryper submit; revenue credits grouped by fund + revenue account with explicitfundIdon each JE line; header org = parent when multi-fund + parent exists. - Files:
RegularDepositManager.tsx,get_deposit_history_pagemigration20260327200000_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
onFocushandler toAccountSearchtrigger button to auto-open the popover on tab-focus. AddeduseEffectto auto-focus theCommandInputsearch field when popover opens, enabling immediate type-to-filter. - P1 (Labels): Renamed all
categoryi18n values from "Category" to "Account" across all 6 locales (en/es/fr/de/zh/th). UpdatedCheckDepositManagerreview card and view dialog to uset('deposits.regular.category')instead of hardcoded "Account". - P2 (§28): Replaced
<Input type="number">with<CurrencyInput>onCheckDepositManageramount field. - P2 (§16 stat tiles): Removed
Banknote/DollarSignicons fromCheckDepositManagerstat tiles (violates "NO icons in stat tiles" rule). AddeduseCountUpanimations. Replaced hardcoded$+.toFixed(2)withformatCurrency(). MatchedRegularDepositManagerpt-6 text-centerlayout. - P2 (formatCurrency): Replaced all remaining hardcoded
$amounts inCheckDepositManager(capture summary, review cards, view dialog) withformatCurrency(). - Files Modified:
AccountSearch.tsx,CheckDepositManager.tsx, 6 localedeposits.jsonfiles - 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
selectedfield toDepositDatainterface (defaults totrue) - 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
RegularDepositManagerandCheckDepositManagerhardcoded'1000'for cash account lookup instead of using thegetDefaultAccountIdsRPC.QuickEntryDrawerused.toISOString().split('T')[0]for date initialization, violating §22. - Root Cause: Legacy code predating the
organization_account_defaultssystem and thetoLocalDateString()utility. - Solution:
- Replaced
accounts.find(a => a.code === '1000')withgetDefaultAccountIds(orgId, ['default_checking'])in both deposit managers (JE creation + memorized transaction paths) - Replaced
new Date().toISOString().split('T')[0]withtoLocalDateString(new Date())inQuickEntryDrawer(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 clearsdeposit_items.donation_id(preserves audit trail)voidDepositBatch()snapshots all donation IDs before mutations + adds fallback JE lookup by org+date+description+amountdeleteDeposit()now soft-deletes linked donations and voids linked JE before hard-deletingdeleteDepositItem()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
ilikepattern + deposit table fallback - DB migration backfilled
deposit_idon 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
fetchAccountsbut 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
depositEligibleEntitiesfilter 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
useMemoto 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
purposefield toDepositDatainterface - Added Purpose dropdown that fetches from
purposestable 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)fromlib/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
AddDonorDialogcomponent fromcomponents/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 localPopover + Commandimplementation. - Backend:
DonorSearchusessearchDonorsAndProspects()(RPC-backedsearch_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 todateUtils.tsthat 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
DonorSearchwraps React Query + RPC autocomplete; field linkage is stored asdonorId/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-popovertobg-card border-borderfor solid background - Files Modified:
RegularDepositManager.tsx- Payer name and soft credit donor dropdownsCheckDepositManager.tsx- Soft credit donor dropdownDonationsManager.tsx- All donor search dropdowns (3 instances)- Pattern: Use
bg-card border border-borderfor 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):
AccountSearchover the fund’s chart (revenue accounts). The default selection comes only from the fund’s org-owneddonations_revenuemapping (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 depositsdeposits: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-owneddonations_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 depositcurrentDeposit.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 stateINCOME_CATEGORIES- Category listDonorSearch- Shared payer donor/prospect lookup componentsearchDonorsAndProspects- RPC-backed donor/prospect autocompletefetchPurposes- Fetches purposes for selected nonprofit- UI components (Card, Button, Input, Select, etc.)
External Libraries
lucide-react- Iconssonner- 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
- 08-CHECK-DEPOSIT-MANAGER.md — same batch-then-complete pattern (capture/review → Complete)
- 07-REIMBURSEMENTS-MANAGER.md — Submit tab capture → review → Complete (staged batch)
- 06-EXPENSES-MANAGER.md — Add Expense / Scan Receipt shares capture UX with the above
- 04-GENERAL-LEDGER.md
- 09-RECONCILIATION-MANAGER.md
- 01-DATA-SCHEMA.md
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.00Batch 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