Kontoauszug verbuchen - Beschriftung verbessert.
[kivitendo-erp.git] / SL / Controller / BankTransaction.pm
index 0d60995..50c1519 100644 (file)
@@ -178,6 +178,8 @@ sub action_create_invoice {
   $self->{transaction} = SL::DB::Manager::BankTransaction->find_by(id => $::form->{bt_id});
   my $vendor_of_transaction = SL::DB::Manager::Vendor->find_by(account_number => $self->{transaction}->{remote_account_number});
 
+  my $use_vendor_filter = $self->{transaction}->{remote_account_number} && $vendor_of_transaction;
+
   my $drafts = SL::DB::Manager::Draft->get_all(where => [ module => 'ap'] , with_objects => 'employee');
 
   my @filtered_drafts;
@@ -191,15 +193,15 @@ sub action_create_invoice {
   }
 
   #Filter drafts
-  @filtered_drafts = grep { $_->{vendor_id} == $vendor_of_transaction->id } @filtered_drafts if $vendor_of_transaction;
+  @filtered_drafts = grep { $_->{vendor_id} == $vendor_of_transaction->id } @filtered_drafts if $use_vendor_filter;
 
   my $all_vendors = SL::DB::Manager::Vendor->get_all();
 
   $self->render('bank_transactions/create_invoice', { layout  => 0 },
       title      => t8('Create invoice'),
       DRAFTS     => \@filtered_drafts,
-      vendor_id  => $vendor_of_transaction ? $vendor_of_transaction->id : undef,
-      vendor_name => $vendor_of_transaction ? $vendor_of_transaction->name : undef,
+      vendor_id  => $use_vendor_filter ? $vendor_of_transaction->id : undef,
+      vendor_name => $use_vendor_filter ? $vendor_of_transaction->name : undef,
       ALL_VENDORS => $all_vendors,
       limit      => $myconfig{vclimit},
       callback   => $self->url_for(action                => 'list',
@@ -216,9 +218,8 @@ sub action_ajax_payment_suggestion {
   # create an HTML blob to be used by the js function add_invoices in templates/webpages/bank_transactions/list.html
   # and return encoded as JSON
 
-  my $bt = SL::DB::Manager::BankTransaction->find_by( id => $::form->{bt_id} );
-  my $invoice = SL::DB::Manager::Invoice->find_by( id => $::form->{prop_id} );
-  $invoice = SL::DB::Manager::PurchaseInvoice->find_by( id => $::form->{prop_id} ) unless $invoice;
+  my $bt      = SL::DB::Manager::BankTransaction->find_by( id => $::form->{bt_id} );
+  my $invoice = SL::DB::Manager::Invoice->find_by( id => $::form->{prop_id} ) || SL::DB::Manager::PurchaseInvoice->find_by( id => $::form->{prop_id} );
 
   die unless $bt and $invoice;
 
@@ -228,7 +229,7 @@ sub action_ajax_payment_suggestion {
   $html .= SL::Presenter->input_tag('invoice_ids.' . $::form->{bt_id} . '[]', $::form->{prop_id} , type => 'hidden');
   # better in template code - but how to ajax this
   $html .= SL::Presenter->escape(t8('Invno.') . ': ' . $invoice->invnumber . ' ');
-  $html .= SL::Presenter->escape(t8('Amount') . ': ' . $::form->format_amount(\%::myconfig, $invoice->open_amount, 2) . ' ');
+  $html .= SL::Presenter->escape(t8('Open amount') . ': ' . $::form->format_amount(\%::myconfig, $invoice->open_amount, 2) . ' ');
   $html .= SL::Presenter->select_tag('invoice_skontos.' . $::form->{bt_id} . '[]', \@select_options,
                                               value_key => 'payment_type',
                                               title_key => 'display' ) if @select_options;
@@ -250,6 +251,7 @@ sub action_filter_drafts {
 
   foreach my $draft ( @{ $drafts } ) {
     my $draft_as_object = YAML::Load($draft->form);
+    next unless $draft_as_object->{vendor_id};  # we cannot filter for vendor name, if this is a gl draft
     my $vendor = SL::DB::Manager::Vendor->find_by(id => $draft_as_object->{vendor_id});
     $draft->{vendor} = $vendor->name;
     $draft->{vendor_id} = $vendor->id;
@@ -342,9 +344,7 @@ sub action_ajax_accept_invoices {
 
   my @selected_invoices;
   foreach my $invoice_id (@{ $::form->{invoice_id} || [] }) {
-    my $invoice_object = SL::DB::Manager::Invoice->find_by(id => $invoice_id);
-    $invoice_object ||= SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id);
-
+    my $invoice_object = SL::DB::Manager::Invoice->find_by(id => $invoice_id) || SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id);
     push @selected_invoices, $invoice_object;
   }
 
@@ -357,29 +357,54 @@ sub action_save_invoices {
   my ($self) = @_;
 
   my $invoice_hash = delete $::form->{invoice_ids}; # each key (the bt line with a bt_id) contains an array of invoice_ids
+
+  # e.g. three partial payments with bt_ids 54, 55 and 56 for invoice with id 74:
+  # $invoice_hash = {
+  #         '55' => [
+  #                 '74'
+  #               ],
+  #         '54' => [
+  #                 '74'
+  #               ],
+  #         '56' => [
+  #                 '74'
+  #               ]
+  #       };
+  #
+  # or if the payment with bt_id 44 is used to pay invoices with ids 50, 51 and 52
+  # $invoice_hash = {
+  #           '44' => [ '50', '51', 52' ]
+  #         };
+
   my $skonto_hash  = delete $::form->{invoice_skontos} || {}; # array containing the payment type, could be empty
 
   # a bank_transaction may be assigned to several invoices, i.e. a customer
   # might pay several open invoices with one transaction
 
   while ( my ($bt_id, $invoice_ids) = each(%$invoice_hash) ) {
-    my $bank_transaction = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
-    my $sign = $bank_transaction->amount < 0 ? -1 : 1;
+    my $bank_transaction      = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
+    my $sign                  = $bank_transaction->amount < 0 ? -1 : 1;
     my $amount_of_transaction = $sign * $bank_transaction->amount;
 
     my @invoices;
     foreach my $invoice_id (@{ $invoice_ids }) {
       push @invoices, (SL::DB::Manager::Invoice->find_by(id => $invoice_id) || SL::DB::Manager::PurchaseInvoice->find_by(id => $invoice_id));
     }
-    @invoices = sort { return 1 if ($a->is_sales and $a->amount > 0);
-                          return 1 if (!$a->is_sales and $a->amount < 0);
-                          return -1; } @invoices                if $bank_transaction->amount > 0;
-    @invoices = sort { return -1 if ($a->is_sales and $a->amount > 0);
+    @invoices = sort { return 1 if ( $a->is_sales and $a->amount > 0);
+                       return 1 if (!$a->is_sales and $a->amount < 0);
+                       return -1;
+                     } @invoices if $bank_transaction->amount > 0;
+    @invoices = sort { return -1 if ( $a->is_sales and $a->amount > 0);
                        return -1 if (!$a->is_sales and $a->amount < 0);
-                       return 1; } @invoices                    if $bank_transaction->amount < 0;
+                       return 1;
+                     } @invoices if $bank_transaction->amount < 0;
+
+    my $max_invoices = scalar(@invoices);
+    my $n_invoices   = 0;
 
     foreach my $invoice (@invoices) {
 
+      $n_invoices++ ;
       # Check if bank_transaction already has a link to the invoice, may only be linked once per invoice
       # This might be caused by the user reloading a page and resending the form
       die t8("Bank transaction with id #1 has already been linked to #2.", $bank_transaction->id, $invoice->displayable_name)
@@ -399,13 +424,13 @@ sub action_save_invoices {
         last;
       }
       # pay invoice or go to the next bank transaction if the amount is not sufficiently high
-      if ($invoice->open_amount <= $amount_of_transaction) {
+      if ($invoice->open_amount <= $amount_of_transaction && $n_invoices < $max_invoices) {
         # first calculate new bank transaction amount ...
         if ($invoice->is_sales) {
           $amount_of_transaction -= $sign * $invoice->open_amount;
           $bank_transaction->invoice_amount($bank_transaction->invoice_amount + $invoice->open_amount);
         } else {
-          $amount_of_transaction += $sign * $invoice->open_amount if (!$invoice->is_sales);
+          $amount_of_transaction += $sign * $invoice->open_amount;
           $bank_transaction->invoice_amount($bank_transaction->invoice_amount - $invoice->open_amount);
         }
         # ... and then pay the invoice
@@ -414,14 +439,13 @@ sub action_save_invoices {
                               amount       => $invoice->open_amount,
                               payment_type => $payment_type,
                               transdate    => $bank_transaction->transdate->to_kivitendo);
-      } else {
+      } else { # use the whole amount of the bank transaction for the invoice, overpay the invoice if necessary
         $invoice->pay_invoice(chart_id     => $bank_transaction->local_bank_account->chart_id,
                               trans_id     => $invoice->id,
                               amount       => $amount_of_transaction,
                               payment_type => $payment_type,
                               transdate    => $bank_transaction->transdate->to_kivitendo);
-        $bank_transaction->invoice_amount($bank_transaction->amount) if $invoice->is_sales;
-        $bank_transaction->invoice_amount($bank_transaction->amount) if !$invoice->is_sales;
+        $bank_transaction->invoice_amount($bank_transaction->amount);
         $amount_of_transaction = 0;
       }
 
@@ -434,6 +458,18 @@ sub action_save_invoices {
           );
 
       SL::DB::RecordLink->new(@props)->save;
+
+      # "close" a sepa_export_item if it exists
+      # code duplicated in action_save_proposals!
+      # currently only works, if there is only exactly one open sepa_export_item
+      if ( my $seis = $invoice->find_sepa_export_items({ executed => 0 }) ) {
+        if ( scalar @$seis == 1 ) {
+          # moved the execution and the check for sepa_export into a method,
+          # this isn't part of a transaction, though
+          $seis->[0]->set_executed if $invoice->id == $seis->[0]->arap_id;
+        };
+      };
+
     }
     $bank_transaction->save;
   }
@@ -475,6 +511,17 @@ sub action_save_proposals {
         );
 
     SL::DB::RecordLink->new(@props)->save;
+
+    # code duplicated in action_save_invoices!
+    # "close" a sepa_export_item if it exists
+    # currently only works, if there is only exactly one open sepa_export_item
+    if ( my $seis = $arap->find_sepa_export_items({ executed => 0 }) ) {
+      if ( scalar @$seis == 1 ) {
+        # moved the execution and the check for sepa_export into a method,
+        # this isn't part of a transaction, though
+        $seis->[0]->set_executed if $arap->id == $seis->[0]->arap_id;
+      };
+    };
   }
 
   flash('ok', t8('#1 proposal(s) saved.', scalar @{ $::form->{proposal_ids} }));