diff --git a/client/src/components/BankingKreditorSelector.js b/client/src/components/BankingKreditorSelector.js
index 3d1bb3c..c36258c 100644
--- a/client/src/components/BankingKreditorSelector.js
+++ b/client/src/components/BankingKreditorSelector.js
@@ -11,7 +11,9 @@ import {
CircularProgress,
Typography,
} from '@mui/material';
+import { Add as AddIcon } from '@mui/icons-material';
import AuthService from '../services/AuthService';
+import KreditorService from '../services/KreditorService';
class BankingKreditorSelector extends Component {
constructor(props) {
@@ -19,22 +21,46 @@ class BankingKreditorSelector extends Component {
this.state = {
assignableKreditors: [],
selectedKreditorId: '',
- notes: '',
loading: false,
error: null,
saving: false,
+ showCreateKreditor: false,
+ newKreditor: {
+ name: '',
+ kreditorId: ''
+ },
+ creating: false,
+ validationErrors: []
};
this.authService = new AuthService();
+ this.kreditorService = new KreditorService();
}
componentDidMount() {
this.loadAssignableKreditors();
this.loadExistingAssignment();
+
+ // Pre-fill new kreditor data with description (actual company name) instead of Beguenstigter (banking service name)
+ const prefilledName = this.props.transaction?.description || '';
+ if (prefilledName) {
+ this.setState({
+ newKreditor: {
+ ...this.state.newKreditor,
+ name: prefilledName
+ }
+ });
+ }
}
componentDidUpdate(prevProps) {
- // Reload data when transaction changes
- if (this.props.transaction?.id !== prevProps.transaction?.id) {
+ // Reload data when transaction changes (only for database transactions)
+ const currentTransactionId = this.props.transaction?.id;
+ const prevTransactionId = prevProps.transaction?.id;
+
+ console.log('componentDidUpdate - current:', currentTransactionId, 'prev:', prevTransactionId);
+
+ if (currentTransactionId !== prevTransactionId) {
+ console.log('Transaction changed, reloading assignment');
this.loadExistingAssignment();
}
}
@@ -63,9 +89,18 @@ class BankingKreditorSelector extends Component {
};
loadExistingAssignment = async () => {
- // For CSV transactions, we need to use csv_transaction_id instead of transaction_id
- const transactionId = this.props.transaction?.id || this.props.transaction?.csv_id;
- if (!transactionId) return;
+ // Only load assignments for regular database transactions, not CSV transactions
+ const transactionId = this.props.transaction?.id;
+ console.log('loadExistingAssignment called with:', {
+ transactionId,
+ csv_id: this.props.transaction?.csv_id,
+ fullTransaction: this.props.transaction
+ });
+
+ if (!transactionId) {
+ console.log('Skipping loadExistingAssignment - no transaction ID');
+ return;
+ }
try {
const response = await this.authService.apiCall(
@@ -78,7 +113,6 @@ class BankingKreditorSelector extends Component {
const assignment = assignments[0];
this.setState({
selectedKreditorId: assignment.assigned_kreditor_id || '',
- notes: assignment.notes || '',
});
}
}
@@ -89,16 +123,80 @@ class BankingKreditorSelector extends Component {
};
handleKreditorChange = (event) => {
- this.setState({ selectedKreditorId: event.target.value });
+ const value = event.target.value;
+ if (value === 'create_new') {
+ this.setState({ showCreateKreditor: true, selectedKreditorId: '' });
+ } else {
+ this.setState({ selectedKreditorId: value, showCreateKreditor: false });
+ }
};
- handleNotesChange = (event) => {
- this.setState({ notes: event.target.value });
+ handleNewKreditorChange = (field, value) => {
+ this.setState({
+ newKreditor: {
+ ...this.state.newKreditor,
+ [field]: value
+ },
+ validationErrors: []
+ });
+ };
+
+ generateKreditorId = () => {
+ const randomDigits = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
+ const kreditorId = `70${randomDigits}`;
+
+ this.setState({
+ newKreditor: {
+ ...this.state.newKreditor,
+ kreditorId
+ }
+ });
+ };
+
+ handleCreateKreditor = async () => {
+ const { newKreditor } = this.state;
+
+ // Create regular kreditor data (no IBAN because transaction was processed through banking account)
+ const kreditorDataToValidate = {
+ ...newKreditor,
+ iban: null,
+ is_banking: false, // This is a regular kreditor (actual company) that will be assigned to banking transactions
+ is_manual_assignment: true // This is a manual assignment for a banking transaction, so no IBAN is required
+ };
+
+ // Validate the data
+ const validationErrors = this.kreditorService.validateKreditorData(kreditorDataToValidate);
+ if (validationErrors.length > 0) {
+ this.setState({ validationErrors });
+ return;
+ }
+
+ this.setState({ creating: true, error: null });
+
+ try {
+ const createdKreditor = await this.kreditorService.createKreditor(kreditorDataToValidate);
+
+ // Add the new kreditor to the list and select it
+ this.setState({
+ assignableKreditors: [...this.state.assignableKreditors, createdKreditor],
+ selectedKreditorId: createdKreditor.id,
+ showCreateKreditor: false,
+ creating: false,
+ newKreditor: { name: '', kreditorId: '' },
+ validationErrors: []
+ });
+ } catch (error) {
+ console.error('Error creating kreditor:', error);
+ this.setState({
+ error: error.message,
+ creating: false
+ });
+ }
};
handleSave = async () => {
const { transaction, user, onSave } = this.props;
- const { selectedKreditorId, notes } = this.state;
+ const { selectedKreditorId } = this.state;
if (!selectedKreditorId) {
this.setState({ error: 'Bitte wählen Sie einen Kreditor aus' });
@@ -108,41 +206,52 @@ class BankingKreditorSelector extends Component {
this.setState({ saving: true, error: null });
try {
- // Check if assignment already exists
- const checkResponse = await this.authService.apiCall(
- `/data/banking-transactions/${transaction.id}`
- );
-
let response;
- if (checkResponse && checkResponse.ok) {
- const existingAssignments = await checkResponse.json();
+
+ if (transaction.id) {
+ // Check for existing assignment first
+ const checkResponse = await this.authService.apiCall(
+ `/data/banking-transactions/${transaction.id}`
+ );
- if (existingAssignments.length > 0) {
- // Update existing assignment
- response = await this.authService.apiCall(
- `/data/banking-transactions/${existingAssignments[0].id}`,
- 'PUT',
- {
- assigned_kreditor_id: parseInt(selectedKreditorId),
- notes: notes.trim() || null,
- assigned_by: user?.username || 'Unknown',
- }
- );
- } else {
- // Create new assignment
- response = await this.authService.apiCall(
- '/data/banking-transactions',
- 'POST',
- {
- transaction_id: transaction.id || null,
- csv_transaction_id: transaction.csv_id || transaction.id || null,
- banking_iban: transaction['Kontonummer/IBAN'] || transaction.kontonummer_iban,
- assigned_kreditor_id: parseInt(selectedKreditorId),
- notes: notes.trim() || null,
- assigned_by: user?.username || 'Unknown',
- }
- );
+ if (checkResponse && checkResponse.ok) {
+ const existingAssignments = await checkResponse.json();
+
+ if (existingAssignments.length > 0) {
+ // Update existing assignment
+ response = await this.authService.apiCall(
+ `/data/banking-transactions/${existingAssignments[0].id}`,
+ {
+ method: 'PUT',
+ body: JSON.stringify({
+ assigned_kreditor_id: parseInt(selectedKreditorId),
+ assigned_by: user?.username || 'Unknown',
+ })
+ }
+ );
+ } else {
+ // Create new assignment
+ response = await this.authService.apiCall(
+ '/data/banking-transactions',
+ {
+ method: 'POST',
+ body: JSON.stringify({
+ transaction_id: transaction.isFromCSV ? null : transaction.id,
+ csv_transaction_id: transaction.isFromCSV ? transaction.id : null,
+ banking_iban: transaction['Kontonummer/IBAN'] || transaction.kontonummer_iban,
+ assigned_kreditor_id: parseInt(selectedKreditorId),
+ assigned_by: user?.username || 'Unknown',
+ })
+ }
+ );
+ }
}
+ } else {
+ this.setState({
+ error: 'Transaktion hat keine gültige ID',
+ saving: false
+ });
+ return;
}
if (response && response.ok) {
@@ -170,10 +279,13 @@ class BankingKreditorSelector extends Component {
const {
assignableKreditors,
selectedKreditorId,
- notes,
loading,
error,
- saving
+ saving,
+ showCreateKreditor,
+ newKreditor,
+ creating,
+ validationErrors
} = this.state;
if (loading) {
@@ -210,20 +322,83 @@ class BankingKreditorSelector extends Component {
{kreditor.name} ({kreditor.kreditorId})
))}
+
-
+ {showCreateKreditor && (
+
+
+ Neuen Kreditor erstellen:
+
+
+ {validationErrors.length > 0 && (
+
+
+ {validationErrors.map((error, index) => (
+ - {error}
+ ))}
+
+
+ )}
+
+ this.handleNewKreditorChange('name', e.target.value)}
+ fullWidth
+ size="small"
+ sx={{ mb: 2 }}
+ placeholder="Name des Kreditors"
+ />
+
+
+ this.handleNewKreditorChange('kreditorId', e.target.value)}
+ size="small"
+ placeholder="70001"
+ sx={{ flexGrow: 1 }}
+ />
+
+
+
+
+ Die Kreditor-ID muss mit "70" beginnen, gefolgt von mindestens 3 Ziffern.
+ Keine IBAN erforderlich, da diese Transaktion über ein Banking-Konto abgewickelt wurde.
+
+
+
+ : null}
+ >
+ {creating ? 'Erstellen...' : 'Kreditor erstellen'}
+
+
+
+
+ )}