refactor: change kontonummer to INTEGER, derive sub-account number as parent + suffix (arithmetic)

This commit is contained in:
Matthias Hochmeister
2026-03-30 11:23:07 +02:00
parent 5f25d644f4
commit e4f1d8864a
3 changed files with 26 additions and 22 deletions

View File

@@ -0,0 +1,3 @@
-- Convert kontonummer from TEXT to INTEGER
ALTER TABLE buchhaltung_konten
ALTER COLUMN kontonummer TYPE INTEGER USING kontonummer::INTEGER;

View File

@@ -196,26 +196,26 @@ function KontoDialog({
konten: Konto[]; konten: Konto[];
onSave: (data: KontoFormData) => void; onSave: (data: KontoFormData) => void;
}) { }) {
const empty: KontoFormData = { haushaltsjahr_id: haushaltsjahrId, kontonummer: '', bezeichnung: '', budget_gwg: 0, budget_anlagen: 0, budget_instandhaltung: 0, parent_id: null, notizen: '' }; const empty: KontoFormData = { haushaltsjahr_id: haushaltsjahrId, kontonummer: 0, bezeichnung: '', budget_gwg: 0, budget_anlagen: 0, budget_instandhaltung: 0, parent_id: null, notizen: '' };
const [form, setForm] = useState<KontoFormData>(empty); const [form, setForm] = useState<KontoFormData>(empty);
const selectedParent = konten.find(k => k.id === form.parent_id); const selectedParent = konten.find(k => k.id === form.parent_id);
const parentPrefix = selectedParent ? selectedParent.kontonummer : '';
// suffix = part of kontonummer after parent prefix // suffix = form.kontonummer - parent.kontonummer (arithmetic)
const kontonummerSuffix = form.kontonummer.startsWith(parentPrefix) ? form.kontonummer.slice(parentPrefix.length) : form.kontonummer; const suffixValue = selectedParent ? form.kontonummer - selectedParent.kontonummer : form.kontonummer;
const handleParentChange = (parentId: number | null) => { const handleParentChange = (parentId: number | null) => {
const parent = konten.find(k => k.id === parentId); const parent = konten.find(k => k.id === parentId);
const prefix = parent ? parent.kontonummer : ''; const oldBase = selectedParent ? selectedParent.kontonummer : 0;
// strip old prefix, re-apply new one const currentSuffix = form.kontonummer - oldBase;
const oldPrefix = selectedParent ? selectedParent.kontonummer : ''; const newBase = parent ? parent.kontonummer : 0;
const suffix = form.kontonummer.startsWith(oldPrefix) ? form.kontonummer.slice(oldPrefix.length) : form.kontonummer; setForm(f => ({ ...f, parent_id: parentId, kontonummer: newBase + Math.max(0, currentSuffix) }));
setForm(f => ({ ...f, parent_id: parentId, kontonummer: prefix + suffix }));
}; };
const handleSuffixChange = (suffix: string) => { const handleSuffixChange = (value: string) => {
const digits = suffix.replace(/\D/g, ''); const suffix = parseInt(value, 10);
setForm(f => ({ ...f, kontonummer: parentPrefix + digits })); const base = selectedParent ? selectedParent.kontonummer : 0;
setForm(f => ({ ...f, kontonummer: base + (isNaN(suffix) ? 0 : suffix) }));
}; };
useEffect(() => { useEffect(() => {
@@ -233,15 +233,16 @@ function KontoDialog({
<DialogContent> <DialogContent>
<Stack spacing={2} sx={{ mt: 1 }}> <Stack spacing={2} sx={{ mt: 1 }}>
<TextField <TextField
label="Kontonummer" label={selectedParent ? 'Kontonummer (Suffix)' : 'Kontonummer'}
value={kontonummerSuffix} type="number"
value={suffixValue || ''}
onChange={e => handleSuffixChange(e.target.value)} onChange={e => handleSuffixChange(e.target.value)}
required required
inputProps={{ inputMode: 'numeric', pattern: '[0-9]*' }} inputProps={{ min: 1, step: 1 }}
InputProps={parentPrefix ? { InputProps={selectedParent ? {
startAdornment: <InputAdornment position="start">{parentPrefix}</InputAdornment>, startAdornment: <InputAdornment position="start">{selectedParent.kontonummer} +</InputAdornment>,
} : undefined} } : undefined}
helperText={parentPrefix ? `Vollständige Nummer: ${form.kontonummer || parentPrefix + '…'}` : undefined} helperText={selectedParent ? `Ergibt Kontonummer: ${form.kontonummer}` : undefined}
/> />
<TextField label="Bezeichnung" value={form.bezeichnung} onChange={e => setForm(f => ({ ...f, bezeichnung: e.target.value }))} required /> <TextField label="Bezeichnung" value={form.bezeichnung} onChange={e => setForm(f => ({ ...f, bezeichnung: e.target.value }))} required />
<FormControl fullWidth margin="dense"> <FormControl fullWidth margin="dense">
@@ -268,7 +269,7 @@ function KontoDialog({
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={onClose}>Abbrechen</Button> <Button onClick={onClose}>Abbrechen</Button>
<Button variant="contained" onClick={() => onSave(form)} disabled={!form.bezeichnung || !form.kontonummer || (!!parentPrefix && kontonummerSuffix === '')}>Speichern</Button> <Button variant="contained" onClick={() => onSave(form)} disabled={!form.bezeichnung || !form.kontonummer || (!!selectedParent && suffixValue <= 0)}>Speichern</Button>
</DialogActions> </DialogActions>
</Dialog> </Dialog>
); );

View File

@@ -84,7 +84,7 @@ export interface Konto {
id: number; id: number;
haushaltsjahr_id: number; haushaltsjahr_id: number;
konto_typ_id: number | null; konto_typ_id: number | null;
kontonummer: string; kontonummer: number;
bezeichnung: string; bezeichnung: string;
parent_id: number | null; parent_id: number | null;
budget_gwg: number; budget_gwg: number;
@@ -140,7 +140,7 @@ export interface Transaktion {
aktualisiert_am: string; aktualisiert_am: string;
// Joined fields // Joined fields
konto_bezeichnung?: string; konto_bezeichnung?: string;
konto_kontonummer?: string; konto_kontonummer?: number;
bankkonto_bezeichnung?: string; bankkonto_bezeichnung?: string;
belege?: Beleg[]; belege?: Beleg[];
} }
@@ -219,7 +219,7 @@ export interface BankkontoFormData {
export interface KontoFormData { export interface KontoFormData {
haushaltsjahr_id: number; haushaltsjahr_id: number;
konto_typ_id?: number; konto_typ_id?: number;
kontonummer: string; kontonummer: number;
bezeichnung: string; bezeichnung: string;
budget_gwg: number; budget_gwg: number;
budget_anlagen: number; budget_anlagen: number;