Files
accounted/app/api/bookkeeping/journal-entries/route.ts
T
MattssonandClaude Opus 4.6 a438c50e9c Date filter feature (#24)
* feat: add date sorting support to journal entries API

Add sort_date query parameter (asc/desc) that orders results by
entry_date instead of the default voucher_series + voucher_number.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add date sort toggle to journal entry list

Add ascending/descending sort button next to the missing attachment
filter. Defaults to newest first, toggles between nyast/äldst först.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add date range filter inputs to journal entry list

Add Från/Till text inputs (YYYY-MM-DD) for filtering entries by date
range. Applies on blur or Enter, with an X button to clear both fields.
Both fields are optional and work independently of the sort toggle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-13 17:05:32 +01:00

93 lines
2.7 KiB
TypeScript

import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
import { createJournalEntry } from '@/lib/bookkeeping/engine'
import { ensureInitialized } from '@/lib/init'
import { validateBody } from '@/lib/api/validate'
import { CreateJournalEntrySchema } from '@/lib/api/schemas'
ensureInitialized()
export async function GET(request: Request) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const { searchParams } = new URL(request.url)
const periodId = searchParams.get('period_id')
const status = searchParams.get('status')
const limit = parseInt(searchParams.get('limit') || '50')
const offset = parseInt(searchParams.get('offset') || '0')
const dateFrom = searchParams.get('date_from')
const dateTo = searchParams.get('date_to')
const sortDate = searchParams.get('sort_date') // 'asc' | 'desc'
const dateAscending = sortDate === 'asc'
let query = supabase
.from('journal_entries')
.select('*, lines:journal_entry_lines(*)', { count: 'exact' })
.eq('user_id', user.id)
if (sortDate === 'asc' || sortDate === 'desc') {
query = query
.order('entry_date', { ascending: dateAscending })
.order('voucher_number', { ascending: dateAscending })
} else {
query = query
.order('voucher_series', { ascending: true })
.order('voucher_number', { ascending: true })
}
query = query.range(offset, offset + limit - 1)
if (periodId) {
query = query.eq('fiscal_period_id', periodId)
}
if (status) {
query = query.eq('status', status)
}
if (dateFrom) {
query = query.gte('entry_date', dateFrom)
}
if (dateTo) {
query = query.lte('entry_date', dateTo)
}
const { data, error, count } = await query
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 })
}
return NextResponse.json({ data, count })
}
export async function POST(request: Request) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const validation = await validateBody(request, CreateJournalEntrySchema)
if (!validation.success) return validation.response
const body = validation.data
try {
const entry = await createJournalEntry(supabase, user.id, body)
return NextResponse.json({ data: entry })
} catch (err) {
return NextResponse.json(
{ error: err instanceof Error ? err.message : 'Failed to create journal entry' },
{ status: 400 }
)
}
}