Files
grist-accounting/references/queries.md
Bill Ballou 5693d7b451 Add year-end tax report queries for period-specific reporting
Adds date-parameterized SQL queries for Income Statement, Expense
Detail, Vendor Payment Summary, and General Ledger. These filter
TransactionLines by date range instead of using cumulative balances,
enabling tax year and other period-specific financial reports.
2026-02-22 18:26:19 -05:00

298 lines
7.4 KiB
Markdown

# SQL Queries and Reports
Common queries and financial report templates.
## Contents
- [Common Queries](#common-queries)
- [Financial Reports](#financial-reports)
- [Reconciliation Queries](#reconciliation-queries)
## Common Queries
### Unpaid Bills by Vendor
```sql
SELECT v.Name, b.BillNumber, b.BillDate, b.Amount, b.AmountDue
FROM Bills b
JOIN Vendors v ON b.Vendor = v.id
WHERE b.Status IN ('Open', 'Partial')
ORDER BY b.DueDate
```
### Bills Summary by Vendor
```sql
SELECT v.Name as Vendor, COUNT(b.id) as Bills, SUM(b.Amount) as Total, SUM(b.AmountDue) as Due
FROM Bills b
JOIN Vendors v ON b.Vendor = v.id
GROUP BY v.Name
ORDER BY Total DESC
```
### Account Balances (Non-Zero)
```sql
SELECT Code, Name, Type, Balance
FROM Accounts
WHERE Balance != 0
ORDER BY Code
```
### Owner Reimbursement Balance
```sql
SELECT Balance FROM Accounts WHERE Code = '2203'
```
### Expense Summary by Account
```sql
SELECT a.Code, a.Name, a.Balance
FROM Accounts a
WHERE a.Type = 'Expense' AND a.Balance != 0
ORDER BY a.Balance DESC
```
### Transaction History for Account
```sql
SELECT t.Date, t.Description, t.Reference, tl.Debit, tl.Credit
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
WHERE tl.Account = {account_id}
ORDER BY t.Date DESC
```
### Verify All Transactions Balance
```sql
SELECT id, Description, Total, IsBalanced
FROM Transactions
WHERE IsBalanced = false
```
## Financial Reports
### Balance Sheet
Shows Assets = Liabilities + Equity at a point in time.
**Important:** Parent accounts roll up child balances. Query only top-level parents (Parent = 0) to avoid double-counting.
```sql
-- Assets, Liabilities, Equity (top-level only)
SELECT Code, Name, Type, Balance
FROM Accounts
WHERE Type IN ('Asset', 'Liability', 'Equity')
AND Parent = 0
ORDER BY Type, Code
```
```sql
-- Net Income (for Equity section)
SELECT
COALESCE(SUM(CASE WHEN Type = 'Income' THEN Balance ELSE 0 END), 0) -
COALESCE(SUM(CASE WHEN Type = 'Expense' THEN Balance ELSE 0 END), 0) as NetIncome
FROM Accounts
WHERE Type IN ('Income', 'Expense')
AND id NOT IN (SELECT DISTINCT Parent FROM Accounts WHERE Parent != 0)
```
**Presentation:**
| **Assets** | |
|---|---:|
| Cash & Bank Accounts | $X.XX |
| Accounts Receivable | $X.XX |
| **Total Assets** | **$X.XX** |
| **Liabilities** | |
|---|---:|
| Accounts Payable | $X.XX |
| Due to Owner | $X.XX |
| **Total Liabilities** | **$X.XX** |
| **Equity** | |
|---|---:|
| Retained Earnings | $X.XX |
| Net Income (Loss) | $X.XX |
| **Total Equity** | **$X.XX** |
| **Total Liabilities + Equity** | **$X.XX** |
### Income Statement
Shows Revenue - Expenses = Net Income for a period.
```sql
SELECT Code, Name, Type, Balance
FROM Accounts
WHERE Type IN ('Income', 'Expense')
AND Balance != 0
AND id NOT IN (SELECT DISTINCT Parent FROM Accounts WHERE Parent != 0)
ORDER BY Type DESC, Code
```
**Presentation:**
| **Income** | |
|---|---:|
| Service Revenue | $X.XX |
| **Total Income** | **$X.XX** |
| **Expenses** | |
|---|---:|
| Software & Subscriptions | $X.XX |
| Professional Services | $X.XX |
| **Total Expenses** | **$X.XX** |
| **Net Income (Loss)** | **$X.XX** |
### Trial Balance
Lists all accounts with non-zero balances. Debits should equal Credits.
```sql
SELECT
Code,
Name,
Type,
CASE WHEN Type IN ('Asset', 'Expense') THEN Balance ELSE 0 END as Debit,
CASE WHEN Type IN ('Liability', 'Equity', 'Income') THEN Balance ELSE 0 END as Credit
FROM Accounts
WHERE Balance != 0
AND id NOT IN (SELECT DISTINCT Parent FROM Accounts WHERE Parent != 0)
ORDER BY Code
```
### Accounts Payable Aging
```sql
SELECT
v.Name as Vendor,
b.BillNumber,
b.BillDate,
b.DueDate,
b.AmountDue,
CASE
WHEN b.DueDate >= strftime('%s', 'now') THEN 'Current'
WHEN b.DueDate >= strftime('%s', 'now') - 2592000 THEN '1-30 Days'
WHEN b.DueDate >= strftime('%s', 'now') - 5184000 THEN '31-60 Days'
ELSE '60+ Days'
END as Aging
FROM Bills b
JOIN Vendors v ON b.Vendor = v.id
WHERE b.Status IN ('Open', 'Partial')
ORDER BY b.DueDate
```
## Year-End Tax Reports
Date-parameterized queries for tax year reporting. Replace `{start_date}` and `{end_date}` with Unix timestamps (e.g., 2025: start=1735776000, end=1767312000).
### Period Income Statement (P&L)
Sums TransactionLines by Income/Expense account for a date range (Schedule C core data):
```sql
SELECT a.Code, a.Name, a.Type,
SUM(tl.Debit) as Debits, SUM(tl.Credit) as Credits
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
JOIN Accounts a ON tl.Account = a.id
WHERE a.Type IN ('Income', 'Expense')
AND t.Date >= {start_date} AND t.Date < {end_date}
GROUP BY a.Code, a.Name, a.Type
ORDER BY a.Type DESC, a.Code
```
### Period Expense Detail
All expense transactions with individual line items, grouped by account:
```sql
SELECT t.Date, a.Code, a.Name, t.Description, t.Reference, tl.Debit, tl.Credit
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
JOIN Accounts a ON tl.Account = a.id
WHERE a.Type = 'Expense'
AND t.Date >= {start_date} AND t.Date < {end_date}
ORDER BY a.Code, t.Date
```
### Vendor Payment Summary
Total payments per vendor for 1099 determination ($600+ threshold):
```sql
SELECT v.Name as Vendor, COUNT(bp.id) as Payments, SUM(bp.Amount) as TotalPaid
FROM BillPayments bp
JOIN Bills b ON bp.Bill = b.id
JOIN Vendors v ON b.Vendor = v.id
WHERE bp.PaymentDate >= {start_date} AND bp.PaymentDate < {end_date}
GROUP BY v.Name
ORDER BY TotalPaid DESC
```
### Period General Ledger
All transactions in the period with full detail:
```sql
SELECT t.Date, t.Description, t.Reference, t.Status,
a.Code, a.Name, tl.Debit, tl.Credit, tl.Memo
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
JOIN Accounts a ON tl.Account = a.id
WHERE t.Date >= {start_date} AND t.Date < {end_date}
ORDER BY t.Date, t.id, a.Code
```
### Point-in-Time Balance Sheet / Trial Balance
Use `Accounts.Balance` (cumulative) for businesses that started tracking in Grist during the reporting year. If prior-year data exists, subtract beginning-of-year balances. See the [Financial Reports](#financial-reports) section for balance queries.
> **Note**: If `tl.Transaction` JOIN fails due to the reserved word issue, fall back to `get_records` on TransactionLines + programmatic joining.
## Reconciliation Queries
### Cleared Balance for Bank Account
Use `get_records` to avoid the `Transaction` reserved word issue:
```python
# Step 1: Get all TransactionLines for Checking (id=14)
lines = get_records("TransactionLines", filter={"Account": [14]})
# Step 2: Get cleared transaction IDs
txn_ids = list(set(line["Transaction"] for line in lines))
cleared = sql_query(f"SELECT id FROM Transactions WHERE Status = 'Cleared' AND id IN (...)")
cleared_ids = set(row["id"] for row in cleared)
# Step 3: Sum Debit - Credit for cleared lines
cleared_balance = sum(
line["Debit"] - line["Credit"]
for line in lines
if line["Transaction"] in cleared_ids
)
```
### Outstanding Items (Not Cleared by Bank)
```sql
SELECT t.id, t.Date, t.Description, t.Status,
tl.Debit, tl.Credit
FROM TransactionLines tl
JOIN Transactions t ON tl.Transaction = t.id
WHERE tl.Account = 14
AND t.Status != 'Cleared'
ORDER BY t.Date
```
### Reconciliation History
```sql
SELECT id, StatementDate, StatementBalance,
ClearedBalance, Difference, Status
FROM Reconciliations
WHERE Account = 14
ORDER BY StatementDate DESC
```
### Active Bank Rules
```python
get_records("BankRules", filter={"Account": [14], "IsActive": [true]})
```