'use client' import { useState, useEffect } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { useToast } from '@/components/ui/use-toast' import { Plus, Trash2 } from 'lucide-react' import type { CreateJournalEntryLineInput, FiscalPeriod } from '@/types' interface Props { onCreated?: () => void } interface FormLine { account_number: string debit_amount: string credit_amount: string line_description: string } export default function JournalEntryForm({ onCreated }: Props) { const { toast } = useToast() const [periods, setPeriods] = useState([]) const [selectedPeriod, setSelectedPeriod] = useState('') const [entryDate, setEntryDate] = useState(new Date().toISOString().split('T')[0]) const [description, setDescription] = useState('') const [lines, setLines] = useState([ { account_number: '', debit_amount: '', credit_amount: '', line_description: '' }, { account_number: '', debit_amount: '', credit_amount: '', line_description: '' }, ]) const [isSubmitting, setIsSubmitting] = useState(false) useEffect(() => { fetchPeriods() }, []) async function fetchPeriods() { const res = await fetch('/api/bookkeeping/fiscal-periods') const { data } = await res.json() setPeriods(data || []) if (data && data.length > 0) { setSelectedPeriod(data[0].id) } } const addLine = () => { setLines([ ...lines, { account_number: '', debit_amount: '', credit_amount: '', line_description: '' }, ]) } const removeLine = (index: number) => { if (lines.length <= 2) return setLines(lines.filter((_, i) => i !== index)) } const updateLine = (index: number, field: keyof FormLine, value: string) => { const updated = [...lines] updated[index] = { ...updated[index], [field]: value } // If entering debit, clear credit and vice versa if (field === 'debit_amount' && value) { updated[index].credit_amount = '' } else if (field === 'credit_amount' && value) { updated[index].debit_amount = '' } setLines(updated) } const totalDebit = lines.reduce((sum, l) => sum + (parseFloat(l.debit_amount) || 0), 0) const totalCredit = lines.reduce((sum, l) => sum + (parseFloat(l.credit_amount) || 0), 0) const isBalanced = Math.abs(totalDebit - totalCredit) < 0.01 && totalDebit > 0 const handleSubmit = async () => { if (!selectedPeriod || !description || !isBalanced) return setIsSubmitting(true) const entryLines: CreateJournalEntryLineInput[] = lines .filter((l) => l.account_number && (l.debit_amount || l.credit_amount)) .map((l) => ({ account_number: l.account_number, debit_amount: parseFloat(l.debit_amount) || 0, credit_amount: parseFloat(l.credit_amount) || 0, line_description: l.line_description || undefined, })) const res = await fetch('/api/bookkeeping/journal-entries', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ fiscal_period_id: selectedPeriod, entry_date: entryDate, description, source_type: 'manual', lines: entryLines, }), }) const result = await res.json() if (result.error) { toast({ title: 'Fel', description: result.error, variant: 'destructive', }) } else { toast({ title: 'Verifikation skapad', description: `Verifikation ${result.data?.voucher_series}${result.data?.voucher_number} har skapats.`, }) // Reset form setDescription('') setLines([ { account_number: '', debit_amount: '', credit_amount: '', line_description: '' }, { account_number: '', debit_amount: '', credit_amount: '', line_description: '' }, ]) onCreated?.() } setIsSubmitting(false) } return ( Ny verifikation
setEntryDate(e.target.value)} />
setDescription(e.target.value)} placeholder="Verifikationstext..." />
{/* Entry lines */}
{lines.map((line, index) => ( ))}
Konto Beskrivning Debet Kredit
updateLine(index, 'account_number', e.target.value)} placeholder="1930" className="font-mono h-8" maxLength={4} /> updateLine(index, 'line_description', e.target.value)} placeholder="Radtext..." className="h-8" /> updateLine(index, 'debit_amount', e.target.value)} placeholder="0,00" className="text-right h-8" min="0" step="0.01" /> updateLine(index, 'credit_amount', e.target.value)} placeholder="0,00" className="text-right h-8" min="0" step="0.01" />
Summa {totalDebit.toLocaleString('sv-SE', { minimumFractionDigits: 2 })} {totalCredit.toLocaleString('sv-SE', { minimumFractionDigits: 2 })}
{!isBalanced && totalDebit > 0 && (

Differens: {Math.abs(totalDebit - totalCredit).toLocaleString('sv-SE', { minimumFractionDigits: 2 })} kr

)}
) }