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}) ))} + + + Neuen Kreditor erstellen + - + {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. + + + + + + +
+ )}