import React, { Component } from 'react';
import {
Box,
Typography,
Button,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
TextField,
Select,
MenuItem,
FormControl,
InputLabel,
IconButton,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Alert,
Chip
} from '@mui/material';
import {
Add as AddIcon,
Delete as DeleteIcon,
Edit as EditIcon,
Save as SaveIcon,
Cancel as CancelIcon
} from '@mui/icons-material';
import AuthService from '../services/AuthService';
class AccountingItemsManager extends Component {
constructor(props) {
super(props);
this.state = {
accountingItems: [],
kontos: [],
bus: [],
loading: true,
editingItem: null,
showCreateDialog: false,
showCreateKontoDialog: false,
jtlKontierung: null,
newItem: {
umsatz_brutto: '',
soll_haben_kz: 'S',
konto: '',
bu: '',
rechnungsnummer: '',
buchungstext: ''
},
newKonto: {
konto: '',
name: ''
},
error: null,
saving: false
};
this.authService = new AuthService();
}
componentDidMount() {
this.loadData();
this.loadJtlKontierung();
}
loadData = async () => {
try {
// Load accounting items for this transaction
await this.loadAccountingItems();
// Load Konto and BU options
await Promise.all([
this.loadKontos(),
this.loadBUs()
]);
this.setState({ loading: false });
} catch (error) {
console.error('Error loading data:', error);
this.setState({
error: 'Fehler beim Laden der Daten',
loading: false
});
}
};
loadJtlKontierung = async () => {
try {
const { transaction } = this.props;
if (!transaction || !transaction.jtlId) {
this.setState({ jtlKontierung: undefined });
return;
}
const response = await this.authService.apiCall(`/data/jtl-kontierung/${transaction.jtlId}`);
if (!response) return;
if (response.ok) {
const data = await response.json();
this.setState({ jtlKontierung: data });
} else {
const err = await response.json();
console.error('Failed to load JTL Kontierung:', err);
this.setState({ jtlKontierung: undefined });
}
} catch (e) {
console.error('Error loading JTL Kontierung:', e);
this.setState({ jtlKontierung: undefined });
}
}
loadAccountingItems = async () => {
const { transaction } = this.props;
if (!transaction?.id) return;
try {
const response = await this.authService.apiCall(`/data/accounting-items/${transaction.id}`);
if (response && response.ok) {
const items = await response.json();
this.setState({ accountingItems: items });
}
} catch (error) {
console.error('Error loading accounting items:', error);
}
};
loadKontos = async () => {
try {
const response = await this.authService.apiCall('/data/kontos');
if (response && response.ok) {
const kontos = await response.json();
this.setState({ kontos });
}
} catch (error) {
console.error('Error loading kontos:', error);
}
};
loadBUs = async () => {
try {
const response = await this.authService.apiCall('/data/bus');
if (response && response.ok) {
const bus = await response.json();
this.setState({ bus });
}
} catch (error) {
console.error('Error loading BUs:', error);
}
};
handleCreateItem = () => {
const { transaction } = this.props;
this.setState({
showCreateDialog: true,
newItem: {
umsatz_brutto: Math.abs(transaction.numericAmount || 0).toString(),
soll_haben_kz: (transaction.numericAmount || 0) >= 0 ? 'H' : 'S',
konto: '',
bu: '',
rechnungsnummer: '',
buchungstext: transaction.description || ''
}
});
};
handleSaveItem = async () => {
const { transaction } = this.props;
const { newItem } = this.state;
if (!newItem.umsatz_brutto || !newItem.konto) {
this.setState({ error: 'Betrag und Konto sind erforderlich' });
return;
}
this.setState({ saving: true, error: null });
try {
const itemData = {
...newItem,
transaction_id: transaction.isFromCSV ? null : transaction.id,
csv_transaction_id: transaction.isFromCSV ? transaction.id : null,
buchungsdatum: transaction.parsed_date || new Date().toISOString().split('T')[0]
};
const response = await this.authService.apiCall('/data/accounting-items', {
method: 'POST',
body: JSON.stringify(itemData)
});
if (response && response.ok) {
await this.loadAccountingItems();
this.setState({
showCreateDialog: false,
saving: false,
newItem: {
umsatz_brutto: '',
soll_haben_kz: 'S',
konto: '',
bu: '',
rechnungsnummer: '',
buchungstext: ''
}
});
} else {
const errorData = await response.json();
this.setState({
error: errorData.error || 'Fehler beim Speichern',
saving: false
});
}
} catch (error) {
console.error('Error saving accounting item:', error);
this.setState({
error: 'Fehler beim Speichern',
saving: false
});
}
};
handleCreateKonto = async () => {
const { newKonto } = this.state;
if (!newKonto.konto || !newKonto.name) {
this.setState({ error: 'Konto-Nummer und Name sind erforderlich' });
return;
}
this.setState({ saving: true, error: null });
try {
const response = await this.authService.apiCall('/data/kontos', {
method: 'POST',
body: JSON.stringify(newKonto)
});
if (response && response.ok) {
await this.loadKontos();
this.setState({
showCreateKontoDialog: false,
saving: false,
newKonto: { konto: '', name: '' }
});
} else {
const errorData = await response.json();
this.setState({
error: errorData.error || 'Fehler beim Erstellen des Kontos',
saving: false
});
}
} catch (error) {
console.error('Error creating konto:', error);
this.setState({
error: 'Fehler beim Erstellen des Kontos',
saving: false
});
}
};
handleDeleteItem = async (itemId) => {
if (!window.confirm('Buchungsposten wirklich löschen?')) return;
try {
const response = await this.authService.apiCall(`/data/accounting-items/${itemId}`, {
method: 'DELETE'
});
if (response && response.ok) {
await this.loadAccountingItems();
}
} catch (error) {
console.error('Error deleting accounting item:', error);
this.setState({ error: 'Fehler beim Löschen' });
}
};
calculateTotal = () => {
return this.state.accountingItems.reduce((sum, item) => {
const amount = parseFloat(item.umsatz_brutto) || 0;
return sum + (item.soll_haben_kz === 'S' ? amount : -amount);
}, 0);
};
render() {
const { transaction } = this.props;
const {
accountingItems,
kontos,
bus,
loading,
showCreateDialog,
showCreateKontoDialog,
newItem,
newKonto,
error,
saving
} = this.state;
if (loading) {
return Lade Buchungsdaten...;
}
const transactionAmount = transaction.numericAmount || 0;
const currentTotal = this.calculateTotal();
const isBalanced = Math.abs(currentTotal - Math.abs(transactionAmount)) < 0.01;
return (
Buchungsposten
}
onClick={this.handleCreateItem}
size="small"
>
Hinzufügen
{error && (
{error}
)}
Transaktionsbetrag: {Math.abs(transactionAmount).toFixed(2)} €
Summe Buchungsposten: {Math.abs(currentTotal).toFixed(2)} €
{transaction?.jtlId && (
Debug: tUmsatzKontierung.data
{this.state.jtlKontierung === undefined
? 'undefined'
: this.state.jtlKontierung === null
? 'null'
: typeof this.state.jtlKontierung === 'object'
? JSON.stringify(this.state.jtlKontierung, null, 2)
: String(this.state.jtlKontierung)}
)}
Betrag
S/H
Konto
BU
Buchungstext
Aktionen
{accountingItems.map((item) => (
{parseFloat(item.umsatz_brutto).toFixed(2)} €
{item.konto} - {item.konto_name}
{item.bu ? `${item.bu} - ${item.bu_name}` : '-'}
{item.buchungstext || '-'}
this.handleDeleteItem(item.id)}
color="error"
>
))}
{accountingItems.length === 0 && (
Keine Buchungsposten vorhanden
)}
{/* Create Item Dialog */}
{/* Create Konto Dialog */}
);
}
}
export default AccountingItemsManager;