commit f36da7b69b6e8f47bab976e827f5b0f8311cf4c5
Author: Geoffrey Richardson <information@kivitendo-premium.de>
Date:   Tue Jun 28 10:44:58 2016 +0200

    "Kontoauszug verbuchen - SEPA-Zahlungen berücksichtigen und schließen
    
    Erstellt man SEPA-Überweisungen für das Bankprogramm, verbucht die
    Zahlungsausgänge aber per "Kontoauszug verbuchen", wird der
    ursprüngliche SEPA-Prozess unterbrochen. Dort war vorgesehen, daß man
    nach dem Import/Export den SEPA-Export manuell abschliesst, wodurch
    automatisch die betroffenen Rechnungen bezahlt wurden, mit dem
    Zahlungsdatum laut SEPA-Export. Entfällt dieser Schritt wegen Verbuchung
    per Kontoauszug bleiben die SEPA-Exporte hingegen immer offen. Außer daß
    die Liste immer weiter wächst hat das auch den Effekt, daß für
    Rechnungen mit noch offenen SEPA-Exports nicht erneut SEPA-Überweisungen
    erstellt werden können, was bei Teilzahlungen aber erforderlich ist.
    
    Mit dieser Erweiterung wird nun beim "Kontoauszug verbuchen" auch
    geprüft, ob es für die Rechnung eine SEPA-Anweisung gibt, und hierfür
    extra Punkte vergeben. Außerdem wird bei erfolgreicher Zahlung der
    Rechnung auch der SEPA-Export für die Rechnung geschlossen.
    
    Wenn dabei festgestellt wird, daß alle Export einer SEPA-Export-Gruppe
    bezahlt sind, wird auch die SEPA-Export-Gruppe geschlossen.

diff --git a/SL/Controller/BankTransaction.pm b/SL/Controller/BankTransaction.pm
index 5821d3eb8..a9a944087 100644
--- a/SL/Controller/BankTransaction.pm
+++ b/SL/Controller/BankTransaction.pm
@@ -436,6 +436,17 @@ sub action_save_invoices {
           );
 
       SL::DB::RecordLink->new(@props)->save;
+
+      # "close" a sepa_export_item if it exists
+      # 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;
   }
diff --git a/SL/DB/BankTransaction.pm b/SL/DB/BankTransaction.pm
index 051245682..1c2a6dc7f 100644
--- a/SL/DB/BankTransaction.pm
+++ b/SL/DB/BankTransaction.pm
@@ -71,6 +71,7 @@ sub get_agreement_with_invoice {
     remote_account_number       => 3,
     skonto_exact_amount         => 5,
     wrong_sign                  => -1,
+    sepa_export_item            => 5,
   );
 
   my ($agreement,$rule_matches);
@@ -114,7 +115,7 @@ sub get_agreement_with_invoice {
 
   #search invoice number in purpose
   my $invnumber = $invoice->invnumber;
-  # invnumbernhas to have at least 3 characters
+  # invnumber has to have at least 3 characters
   my $squashed_purpose = $self->purpose;
   $squashed_purpose =~ s/ //g;
   if (length($invnumber) > 4 && $squashed_purpose =~ /$invnumber/ && $invoice->is_sales){
@@ -206,6 +207,28 @@ sub get_agreement_with_invoice {
     };
   };
 
+  # if there is exactly one non-executed sepa_export_item for the invoice
+  if ( my $seis = $invoice->find_sepa_export_items({ executed => 0 }) ) {
+    if ( scalar @$seis == 1 ) {
+      my $sei = $seis->[0];
+
+      # test for amount and id matching only, sepa transfer date and bank
+      # transaction date needn't match
+      my $arap = $invoice->is_sales ? 'ar' : 'ap';
+      if (    abs($self->amount) == ($sei->amount)
+          && $invoice->id        == $sei->arap_id
+         ) {
+        $agreement += $points{sepa_export_item};
+          $rule_matches .= 'sepa_export_item(' . $points{'sepa_export_item'} . ') ';
+      };
+    } else {
+      # zero or more than one sepa_export_item, do nothing for this invoice
+      # zero: do nothing, no sepa_export_item exists, no match
+      # more than one: does this ever apply? Currently you can't create sepa
+      # exports for invoices that already have a non-executed sepa_export
+    };
+  };
+
   return ($agreement,$rule_matches);
 };
 
diff --git a/SL/DB/SepaExportItem.pm b/SL/DB/SepaExportItem.pm
index b75e05376..0bcab3e3f 100644
--- a/SL/DB/SepaExportItem.pm
+++ b/SL/DB/SepaExportItem.pm
@@ -1,6 +1,7 @@
 package SL::DB::SepaExportItem;
 
 use strict;
+use SL::DB::SepaExport;
 
 use SL::DB::MetaSetup::SepaExportItem;
 
@@ -20,4 +21,28 @@ sub compare_to {
   return $result || ($self->sepa_export_id <=> $other->sepa_export_id) || ($self->id <=> $other->id);
 }
 
+sub set_executed {
+  my ($self) = @_;
+
+  $self->executed(1); # does execution date also need to be set?
+  $self->save;
+  # if all the sepa_export_items in the sepa_export are closed (executed), close the sepa_export
+  if ( SL::DB::Manager::SepaExportItem->get_all_count( where => [ sepa_export_id => $self->sepa_export_id, executed => 0] ) == 0 ) {
+    my $sepa_export = SL::DB::Manager::SepaExport->find_by(id => $self->sepa_export_id);
+    $sepa_export->executed(1);
+    $sepa_export->closed(1);
+    $sepa_export->save(changes_only=>1);
+  };
+};
+
+
+sub arap_id {
+  my ($self) = @_;
+  if ( $self->ar_id ) {
+    return $self->ar_id;
+  } else {
+    return $self->ap_id;
+  };
+};
+
 1;
