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.
298 lines
7.4 KiB
Markdown
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]})
|
|
```
|