Bankimport: Behandlung von Sammelüberweisungen
authorMartin Helmling martin.helmling@octosoft.eu <martin.helmling@octosoft.eu>
Mon, 7 Nov 2016 07:26:11 +0000 (08:26 +0100)
committerMartin Helmling martin.helmling@octosoft.eu <martin.helmling@octosoft.eu>
Mon, 7 Nov 2016 08:44:05 +0000 (09:44 +0100)
Generell werden die SEPA Export-Items aus der Punktebewertung herausgenommn,
dafür wird eine exaktere Prüfung auch mittels des Transaktionstyps ermittelt.
Dadurch werden auch Sammellastschriften/Überweisungen erkannt.

Setzen von Skontotyp, kein Prüfen der Sepaitems mehr in >get_agreement_with_invoice

SL/Controller/BankTransaction.pm
SL/Controller/CsvImport/BankTransaction.pm
SL/DB/BankTransaction.pm
SL/DB/Helper/Payment.pm
SL/SEPA.pm
locale/de/all
templates/webpages/bank_transactions/list.html
templates/webpages/bank_transactions/tabs/all.html
templates/webpages/bank_transactions/tabs/automatic.html

index 68047f3..350ce61 100644 (file)
@@ -23,6 +23,7 @@ use SL::DB::AccTransaction;
 use SL::DB::Tax;
 use SL::DB::Draft;
 use SL::DB::BankAccount;
+use SL::DB::SepaExportItem;
 use SL::DBUtils qw(like);
 use SL::Presenter;
 
@@ -97,23 +98,100 @@ sub action_list {
       @where
     ],
   );
+  $main::lxdebug->message(LXDebug->DEBUG2(),"count bt=".scalar(@{$bank_transactions}." bank_account=".$bank_account->id." chart=".$bank_account->chart_id));
 
-  my $all_open_ar_invoices = SL::DB::Manager::Invoice        ->get_all(where => [amount => { gt => \'paid' }], with_objects => 'customer');
-  my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => [amount => { gt => \'paid' }], with_objects => 'vendor');
+  my $all_open_ar_invoices = SL::DB::Manager::Invoice        ->get_all(where => [amount => { gt => \'paid' }], with_objects => ['customer','payment_terms']);
+  my $all_open_ap_invoices = SL::DB::Manager::PurchaseInvoice->get_all(where => [amount => { gt => \'paid' }], with_objects => ['vendor'  ,'payment_terms']);
+  my $all_open_sepa_export_items = SL::DB::Manager::SepaExportItem->get_all(where => [chart_id => $bank_account->chart_id ,
+                                                                             'sepa_export.executed' => 0, 'sepa_export.closed' => 0 ], with_objects => ['sepa_export']);
+  $main::lxdebug->message(LXDebug->DEBUG2(),"count sepaexport=".scalar(@{$all_open_sepa_export_items}));
 
   my @all_open_invoices;
   # filter out invoices with less than 1 cent outstanding
   push @all_open_invoices, grep { abs($_->amount - $_->paid) >= 0.01 } @{ $all_open_ar_invoices };
   push @all_open_invoices, grep { abs($_->amount - $_->paid) >= 0.01 } @{ $all_open_ap_invoices };
+  $main::lxdebug->message(LXDebug->DEBUG2(),"bank_account=".$::form->{filter}{bank_account}." invoices: ".scalar(@{ $all_open_ar_invoices }).
+                              " + ".scalar(@{ $all_open_ap_invoices })." transactions=".scalar(@{ $bank_transactions }));
+
+  my @all_sepa_invoices;
+  my @all_non_sepa_invoices;
+  my %sepa_exports;
+  # first collect sepa export items to open invoices
+  foreach my $open_invoice (@all_open_invoices){
+    #    my @items =  grep { $_->ap_id == $open_invoice->id ||  $_->ar_id == $open_invoice->id } @{$all_open_sepa_export_items};
+    $open_invoice->{realamount}  = $::form->format_amount(\%::myconfig,$open_invoice->amount,2);
+    $open_invoice->{skonto_type} = 'without_skonto';
+    foreach ( @{$all_open_sepa_export_items}) {
+      if ( $_->ap_id == $open_invoice->id ||  $_->ar_id == $open_invoice->id ) {
+        #$main::lxdebug->message(LXDebug->DEBUG2(),"exitem=".$_->id." for invoice ".$open_invoice->id);
+        $open_invoice->{sepa_export_item} = $_ ;
+        $open_invoice->{skonto_type} = $_->payment_type;
+        $sepa_exports{$_->sepa_export_id} ||= { count => 0, is_ar => 0, amount => 0, proposed => 0, invoices => [], item => $_ };
+        $sepa_exports{$_->sepa_export_id}->{count}++ ;
+        $sepa_exports{$_->sepa_export_id}->{is_ar}++ if  $_->ar_id == $open_invoice->id;
+        $sepa_exports{$_->sepa_export_id}->{amount} += $_->amount;
+        push ( @{ $sepa_exports{$_->sepa_export_id}->{invoices}} , $open_invoice );
+        #$main::lxdebug->message(LXDebug->DEBUG2(),"amount for export id ".$_->sepa_export_id." = ".
+        #                          $sepa_exports{$_->sepa_export_id}->{amount}." count = ".
+        #                          $sepa_exports{$_->sepa_export_id}->{count}." is_ar = ".
+        #                          $sepa_exports{$_->sepa_export_id}->{is_ar} );
+        push @all_sepa_invoices , $open_invoice;
+      }
+    }
+    push @all_non_sepa_invoices , $open_invoice if ! $open_invoice->{sepa_export_item};
+  }
 
   # try to match each bank_transaction with each of the possible open invoices
   # by awarding points
+  @all_open_invoices = @all_non_sepa_invoices;
+  my @proposals;
 
   foreach my $bt (@{ $bank_transactions }) {
-    next unless $bt->{remote_name};  # bank has no name, usually fees, use create invoice to assign
+    ## 5 Stellen hinter dem Komma auf 2 Stellen reduzieren
+    $bt->amount($bt->amount*1);
+    $bt->invoice_amount($bt->invoice_amount*1);
+    $main::lxdebug->message(LXDebug->DEBUG2(),"BT ".$bt->id." amount=".$bt->amount." invoice_amount=".$bt->invoice_amount." remote=". $bt->{remote_name});
+
+    $bt->{proposals} = [];
 
     $bt->{remote_name} .= $bt->{remote_name_1} if $bt->{remote_name_1};
 
+    if ( $self->is_collective_transaction($bt) ) {
+      foreach ( keys  %sepa_exports) {
+        my $factor = ($sepa_exports{$_}->{is_ar}>0?1:-1);
+        #$main::lxdebug->message(LXDebug->DEBUG2(),"Exp ID=".$_." factor=".$factor." compare sum amount ".($sepa_exports{$_}->{amount} *1) ." == ".($bt->amount * $factor));
+        if ( $bt->transactioncode eq '191' && ($sepa_exports{$_}->{amount} * 1) eq ($bt->amount * $factor) ) {
+          ## jupp
+          $bt->{proposals} = $sepa_exports{$_}->{invoices} ;
+          $sepa_exports{$_}->{proposed}=1;
+          #$main::lxdebug->message(LXDebug->DEBUG2(),"has ".scalar($bt->{proposals})." invoices");
+          push(@proposals, $bt);
+          next;
+        }
+      }
+    }
+    next unless $bt->{remote_name};  # bank has no name, usually fees, use create invoice to assign
+
+    foreach ( keys %sepa_exports) {
+      my $factor = ($sepa_exports{$_}->{is_ar}>0?1:-1);
+      #$main::lxdebug->message(LXDebug->DEBUG2(),"exp count=".$sepa_exports{$_}->{count}." factor=".$factor." proposed=".$sepa_exports{$_}->{proposed});
+      if ( $sepa_exports{$_}->{count} == 1 ) {
+        my $oinvoice = @{ $sepa_exports{$_}->{invoices}}[0];
+        my $eitem = $sepa_exports{$_}->{item};
+        $eitem->amount($eitem->amount*1);
+        #$main::lxdebug->message(LXDebug->DEBUG2(),"remote account '".$bt->{remote_account_number}."' bt_amount=". ($bt->amount * $factor));
+        #$main::lxdebug->message(LXDebug->DEBUG2(),"compare with   '".$eitem->vc_iban."' amount=".$eitem->amount);
+        if ( $bt->{remote_account_number} eq $eitem->vc_iban && $eitem->amount eq ($bt->amount * $factor)) {
+          ## jupp
+          $bt->{proposals} = $sepa_exports{$_}->{invoices} ;
+          #$main::lxdebug->message(LXDebug->DEBUG2(),"found invoice");
+          $sepa_exports{$_}->{proposed}=1;
+          push(@proposals, $bt);
+          next;
+        }
+     }
+    }
+
     # try to match the current $bt to each of the open_invoices, saving the
     # results of get_agreement_with_invoice in $open_invoice->{agreement} and
     # $open_invoice->{rule_matches}.
@@ -125,10 +203,9 @@ sub action_list {
 
     foreach my $open_invoice (@all_open_invoices){
       ($open_invoice->{agreement}, $open_invoice->{rule_matches}) = $bt->get_agreement_with_invoice($open_invoice);
+      #  $main::lxdebug->message(LXDebug->DEBUG2(),"agreement=".$open_invoice->{agreement}." rules matches=".$open_invoice->{rule_matches});
     };
 
-    $bt->{proposals} = [];
-
     my $agreement = 15;
     my $min_agreement = 3; # suggestions must have at least this score
 
@@ -153,13 +230,15 @@ sub action_list {
   # * there must be only one exact match
   # * depending on whether sales or purchase the amount has to have the correct sign (so Gutschriften don't work?)
   my $proposal_threshold = 5;
-  my @proposals = grep {
+  my @otherproposals = grep {
        ($_->{agreement} >= $proposal_threshold)
     && (1 == scalar @{ $_->{proposals} })
     && (@{ $_->{proposals} }[0]->is_sales ? abs(@{ $_->{proposals} }[0]->amount - $_->amount) < 0.01
                                           : abs(@{ $_->{proposals} }[0]->amount + $_->amount) < 0.01)
   } @{ $bank_transactions };
 
+  push ( @proposals, @otherproposals);
+
   # sort bank transaction proposals by quality (score) of proposal
   $bank_transactions = [ sort { $a->{agreement} <=> $b->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 1;
   $bank_transactions = [ sort { $b->{agreement} <=> $a->{agreement} } @{ $bank_transactions } ] if $::form->{sort_by} eq 'proposal' and $::form->{sort_dir} == 0;
@@ -169,7 +248,9 @@ sub action_list {
                 title             => t8('Bank transactions MT940'),
                 BANK_TRANSACTIONS => $bank_transactions,
                 PROPOSALS         => \@proposals,
-                bank_account      => $bank_account );
+                bank_account      => $bank_account,
+                ui_tab            => scalar(@proposals) > 0?1:0,
+              );
 }
 
 sub action_assign_invoice {
@@ -373,10 +454,12 @@ sub action_ajax_accept_invoices {
   );
 }
 
-sub action_save_invoices {
+sub 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
+  return 0 if !$::form->{invoice_ids};
+
+  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 = {
@@ -403,16 +486,58 @@ sub action_save_invoices {
 
   $self->problems([]);
 
-  while ( my ($bank_transaction_id, $invoice_ids) = each(%$invoice_hash) ) {
-    push @{ $self->problems }, $self->save_single_bank_transaction(
-      bank_transaction_id => $bank_transaction_id,
-      invoice_ids         => $invoice_ids,
-    );
+  my $count = 0;
+
+  if ( $::form->{proposal_ids} ) {
+    foreach (@{ $::form->{proposal_ids} }) {
+      my  $bank_transaction_id = $_;
+      my  $invoice_ids = $invoice_hash{$_};
+      push @{ $self->problems }, $self->save_single_bank_transaction(
+        bank_transaction_id => $bank_transaction_id,
+        invoice_ids         => $invoice_ids,
+      );
+      $count += scalar( @{$invoice_ids} );
+    }
+  } else {
+    while ( my ($bank_transaction_id, $invoice_ids) = each(%invoice_hash) ) {
+      push @{ $self->problems }, $self->save_single_bank_transaction(
+        bank_transaction_id => $bank_transaction_id,
+        invoice_ids         => $invoice_ids,
+      );
+      $count += scalar( @{$invoice_ids} );
+    }
   }
+  return $count;
+}
+
+sub action_save_invoices {
+  my ($self) = @_;
+  my $count = $self->save_invoices();
+
+  flash('ok', t8('#1 invoice(s) saved.', $count));
 
   $self->action_list();
 }
 
+sub action_save_proposals {
+  my ($self) = @_;
+  if ( $::form->{proposal_ids} ) {
+    my $propcount = scalar(@{ $::form->{proposal_ids} });
+    if ( $propcount > 0 ) {
+      my $count = $self->save_invoices();
+
+      flash('ok', t8('#1 proposal(s) with #2 invoice(s) saved.',  $propcount, $count));
+    }
+  }
+  $self->action_list();
+
+}
+
+sub is_collective_transaction {
+  my ($self, $bt) = @_;
+  return $bt->transactioncode eq "191";
+}
+
 sub save_single_bank_transaction {
   my ($self, %params) = @_;
 
@@ -509,18 +634,19 @@ sub save_single_bank_transaction {
 
       # pay invoice or go to the next bank transaction if the amount is not sufficiently high
       if ($invoice->open_amount <= $amount_of_transaction && $n_invoices < $max_invoices) {
+        my $open_amount = ($payment_type eq 'with_skonto_pt'?$invoice->amount_less_skonto:$invoice->open_amount);
         # 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);
+          $amount_of_transaction -= $sign * $open_amount;
+          $bank_transaction->invoice_amount($bank_transaction->invoice_amount + $open_amount);
         } else {
-          $amount_of_transaction += $sign * $invoice->open_amount;
-          $bank_transaction->invoice_amount($bank_transaction->invoice_amount - $invoice->open_amount);
+          $amount_of_transaction += $sign * $open_amount;
+          $bank_transaction->invoice_amount($bank_transaction->invoice_amount - $open_amount);
         }
         # ... and then pay the invoice
         $invoice->pay_invoice(chart_id     => $bank_transaction->local_bank_account->chart_id,
                               trans_id     => $invoice->id,
-                              amount       => $invoice->open_amount,
+                              amount       => $open_amount,
                               payment_type => $payment_type,
                               transdate    => $bank_transaction->transdate->to_kivitendo);
       } else { # use the whole amount of the bank transaction for the invoice, overpay the invoice if necessary
@@ -590,58 +716,6 @@ sub save_single_bank_transaction {
   return grep { $_ } ($error, @warnings);
 }
 
-sub action_save_proposals {
-  my ($self) = @_;
-
-  foreach my $bt_id (@{ $::form->{proposal_ids} }) {
-    my $bt = SL::DB::Manager::BankTransaction->find_by(id => $bt_id);
-
-    my $arap = SL::DB::Manager::Invoice->find_by(id => $::form->{"proposed_invoice_$bt_id"});
-    $arap    = SL::DB::Manager::PurchaseInvoice->find_by(id => $::form->{"proposed_invoice_$bt_id"}) if not defined $arap;
-
-    # check for existing record_link for that $bt and $arap
-    # do this before any changes to $bt are made
-    die t8("Bank transaction with id #1 has already been linked to #2.", $bt->id, $arap->displayable_name)
-      if _existing_record_link($bt, $arap);
-
-    #mark bt as booked
-    $bt->invoice_amount($bt->amount);
-    $bt->save;
-
-    #pay invoice
-    $arap->pay_invoice(chart_id  => $bt->local_bank_account->chart_id,
-                       trans_id  => $arap->id,
-                       amount    => $arap->amount,
-                       transdate => $bt->transdate->to_kivitendo);
-    $arap->save;
-
-    #create record link
-    my @props = (
-      from_table => 'bank_transactions',
-      from_id    => $bt_id,
-      to_table   => $arap->is_sales ? 'ar' : 'ap',
-      to_id      => $arap->id,
-    );
-
-    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} }));
-
-  $self->action_list();
-}
-
 #
 # filters
 #
index 5397d27..d6a7e87 100644 (file)
@@ -83,26 +83,29 @@ sub check_existing {
   };
 }
 
+sub _displayable_columns {
+ (
+   { name => 'local_bank_code',       description => $::locale->text('Own bank code') },
+   { name => 'local_account_number',  description => $::locale->text('Own bank account number or IBAN') },
+   { name => 'local_bank_account_id', description => $::locale->text('ID of own bank account') },
+   { name => 'remote_bank_code',      description => $::locale->text('Bank code of the goal/source') },
+   { name => 'remote_account_number', description => $::locale->text('Account number of the goal/source') },
+   { name => 'transdate',             description => $::locale->text('Date of transaction') },
+   { name => 'valutadate',            description => $::locale->text('Valuta date') },
+   { name => 'amount',                description => $::locale->text('Amount') },
+   { name => 'currency',              description => $::locale->text('Currency') },
+   { name => 'currency_id',           description => $::locale->text('Currency (database ID)')          },
+   { name => 'remote_name',           description => $::locale->text('Name of the goal/source (if field names remote_name and remote_name_1 exist they will be combined into field "remote_name")') },
+   { name => 'purpose',               description => $::locale->text('Purpose (if field names purpose, purpose1, purpose2 ... exist they will all combined into the field "purpose")') }
+ );
+}
+
 sub setup_displayable_columns {
   my ($self) = @_;
 
   $self->SUPER::setup_displayable_columns;
 
-  $self->add_displayable_columns({ name => 'local_bank_code',       description => $::locale->text('Own bank code') },
-                                 { name => 'local_account_number',  description => $::locale->text('Own bank account number or IBAN') },
-                                 { name => 'local_bank_account_id', description => $::locale->text('ID of own bank account') },
-                                 { name => 'remote_bank_code',      description => $::locale->text('Bank code of the goal/source') },
-                                 { name => 'remote_account_number', description => $::locale->text('Account number of the goal/source') },
-                                 { name => 'transdate',             description => $::locale->text('Date of transaction') },
-                                 { name => 'valutadate',            description => $::locale->text('Valuta date') },
-                                 { name => 'amount',                description => $::locale->text('Amount') },
-                                 { name => 'currency',              description => $::locale->text('Currency') },
-                                 { name => 'currency_id',           description => $::locale->text('Currency (database ID)')          },
-                                 { name => 'remote_name',           description => $::locale->text('Name of the goal/source (if field names remote_name and remote_name_1 exist they will be combined into field "remote_name")') },
-                                 { name => 'purpose',               description => $::locale->text('Purpose (if field names purpose, purpose1, purpose2 ... exist they will all combined into the field "purpose")') },
-                                 { name => 'transactionCode',       description => $::locale->text('Transaction Code') },
-                                 { name => 'transactionText',       description => $::locale->text('Transaction Text') },
-                                 );
+  $self->add_displayable_columns($self->_displayable_columns);
 }
 
 sub check_bank_account {
index 053abb4..e91651a 100644 (file)
@@ -112,6 +112,7 @@ sub get_agreement_with_invoice {
   if ( $invoice->skonto_date && abs(abs($invoice->amount_less_skonto) - abs($self->amount)) < 0.01) {
     $agreement += $points{skonto_exact_amount};
     $rule_matches .= 'skonto_exact_amount(' . $points{'skonto_exact_amount'} . ') ';
+    $invoice->{skonto_type} = 'with_skonto_pt';
   };
 
   #search invoice number in purpose
@@ -208,27 +209,27 @@ 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
-    };
-  };
+#  # 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);
 };
index 2507e45..9ff9216 100644 (file)
@@ -94,7 +94,7 @@ sub pay_invoice {
   if ( $params{'payment_type'} eq 'difference_as_skonto' ) {
     croak "amount $params{amount} doesn't match open amount " . $self->open_amount . ", diff = " . ($params{amount}-$self->open_amount) if $params{amount} && abs($self->open_amount - $params{amount} ) > 0.0000001;
   } elsif ( $params{'payment_type'} eq 'with_skonto_pt' ) {
-    croak "amount $params{amount} doesn't match amount less skonto: " . $self->open_amount . "\n" if $params{amount} && abs($self->amount_less_skonto - $params{amount} ) > 0.0000001;
+    croak "amount $params{amount} doesn't match amount less skonto: " . $self->amount_less_skonto . "\n" if $params{amount} && abs($self->amount_less_skonto - $params{amount} ) > 0.0000001;
     croak "payment type with_skonto_pt can't be used if payments have already been made" if $self->paid != 0;
   };
 
@@ -635,11 +635,12 @@ sub get_payment_select_options_for_bank_transaction {
   die unless $bt;
 
   my $open_amount = $self->open_amount;
-
+  #$main::lxdebug->message(LXDebug->DEBUG2(),"skonto_date=".$self->skonto_date." open amount=".$open_amount);
   my @options;
   if ( $open_amount &&                   # invoice amount not 0
        $self->skonto_date &&             # check whether skonto applies
-       abs(abs($self->amount_less_skonto) - abs($bt->amount)) < 0.01 &&
+       ( abs(abs($self->amount_less_skonto) - abs($bt->amount)) < 0.01 ||
+        ( $bt->transactioncode eq "191" && abs($self->amount_less_skonto) < abs($bt->amount) )) &&
        $self->check_skonto_configuration) {
          if ( $self->within_skonto_period($bt->transdate) ) {
            push(@options, { payment_type => 'without_skonto', display => t8('without skonto') });
index b8cdee0..a9ba2f3 100644 (file)
@@ -46,7 +46,9 @@ sub retrieve_open_invoices {
 
          COALESCE(vc.iban, '') <> '' AND COALESCE(vc.bic, '') <> '' ${mandate} AS vc_bank_info_ok,
 
-         ${arap}.amount - ${arap}.paid - COALESCE(open_transfers.amount, 0) AS open_amount
+         ${arap}.amount - ${arap}.paid - COALESCE(open_transfers.amount, 0) AS open_amount,
+         COALESCE(open_transfers.amount, 0) AS transfer_amount,
+         pt.description as pt_description
 
        FROM ${arap}
        LEFT JOIN ${vc} vc ON (${arap}.${vc}_id = vc.id)
@@ -64,6 +66,7 @@ sub retrieve_open_invoices {
 
        ORDER BY lower(vc.name) ASC, lower(${arap}.invnumber) ASC
 |;
+    #  $main::lxdebug->message(LXDebug->DEBUG2(),"sepa add query:".$query);
 
   my $results = selectall_hashref_query($form, $dbh, $query);
 
index d9ad397..56478f5 100755 (executable)
@@ -20,9 +20,11 @@ $self->{texts} = {
   '#1 additional part(s)'       => '#1 zusätzliche(r) Artikel',
   '#1 dunnings have been deleted' => '#1 Mahnung(en) wurden gelöscht',
   '#1 h'                        => '#1 h',
+  '#1 invoice(s) saved.'        => '#1 Rechnung(en) abgespeichert.',
   '#1 of #2 importable objects were imported.' => '#1 von #2 importierbaren Objekten wurden importiert.',
   '#1 prices were updated.'     => '#1 Preise wurden aktualisiert.',
   '#1 proposal(s) saved.'       => '#1 Vorschläge gespeichert.',
+  '#1 proposal(s) with #2 invoice(s) saved.' => '#1 Vorschlag(e) mit #2 Rechnung(en) abgespeichert',
   '#1 section(s)'               => '#1 Abschnitt(e)',
   '#1 text block(s) back'       => '#1 Textlock/-blöcke vorne',
   '#1 text block(s) front'      => '#1 Textblock/-blöcke hinten',
index c810c8f..54351a9 100644 (file)
 [% IF FORM.filter.todate %]   [% 'to (date)' | $T8 %] [% FORM.filter.todate %][% END %]
 </p>
 
-<form method="post" id="list_form">
-[% L.hidden_tag('filter.bank_account', FORM.filter.bank_account) %]
-[% L.hidden_tag('filter.fromdate', FORM.filter.fromdate) %]
-[% L.hidden_tag('filter.todate',   FORM.filter.todate) %]
-
-<div class="tabwidget">
+<div id="bt_tabs" class="tabwidget">
   <ul>
-    <li><a href="#all" onclick="show_invoice_button();">[% 'All transactions' | $T8 %]</a></li>
-    <li><a href="#automatic" onclick="show_proposal_button();">[% 'Proposals' | $T8 %]</a></li>
+    <li><a href="#all">[% 'All transactions' | $T8 %]</a></li>
+    <li><a href="#automatic">[% 'Proposals' | $T8 %]</a></li>
   </ul>
 
   <div id="all">[% PROCESS "bank_transactions/tabs/all.html" %]</div>
   <div id="automatic">[% PROCESS "bank_transactions/tabs/automatic.html" %]</div>
 </div>
 
-[% L.hidden_tag('action', 'BankTransaction/dispatch') %]
-[% L.submit_tag('action_save_invoices', LxERP.t8('Save invoices')) %]
-[% L.submit_tag('action_save_proposals', LxERP.t8('Save proposals'), style='display: none') %]
-
-</form>
 
 <script type="text/javascript">
 <!--
@@ -49,16 +39,6 @@ $(function() {
   });
 });
 
-function show_invoice_button () {
-  $("#action_save_proposals").hide();
-  $("#action_save_invoices").show();
-}
-
-function show_proposal_button () {
-  $("#action_save_invoices").hide();
-  $("#action_save_proposals").show();
-}
-
 function assign_invoice(bt_id) {
   kivi.popup_dialog({
     url:    'controller.pl?action=BankTransaction/assign_invoice',
@@ -103,5 +83,6 @@ function create_invoice(bt_id) {
   return true;
 }
 
+$.cookie('jquery_ui_tab_bt_tabs', [% ui_tab %] );
 //-->
 </script>
index 45aec15..4785497 100644 (file)
@@ -1,6 +1,12 @@
 [%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
 
 [% SET debug=1 %]
+<form method="post" id="list_form">
+[% L.hidden_tag('filter.bank_account', FORM.filter.bank_account) %]
+[% L.hidden_tag('filter.fromdate', FORM.filter.fromdate) %]
+[% L.hidden_tag('filter.todate',   FORM.filter.todate) %]
+[% L.hidden_tag('action', 'BankTransaction/dispatch') %]
+[% L.hidden_tag('ui_tab', ui_tab) %]
 
  <table id="bt_list">
   <thead>
@@ -45,6 +51,7 @@
         [% END %]
     </th>
     <th>[% 'Purpose' | $T8 %]</th>
+    <th>[% 'Type' | $T8 %]</th>
     <th>[% IF FORM.sort_by == 'remote_account_number'%]
           <a href="controller.pl?action=BankTransaction/list&filter.bank_account=[% bank_account.id %]&sort_by=remote_account_number&sort_dir=[% 1 - FORM.sort_dir %]" class="sort_link">
             [% 'Remote account number' | $T8 %][% IF FORM.sort_dir == 0 %]<img border="0" src="image/down.png">[% ELSE %]<img border="0" src="image/up.png">[% END %]</a>
@@ -86,7 +93,7 @@
       [% FOREACH prop = bt.proposals %]
         <div name='[% prop.id %]'>
          <a href=# onclick="add_invoices('[% bt.id %]', '[% prop.id %]', '[% HTML.escape(prop.invnumber) %]');"
-            title="<table><tr><th></th><th>[% 'Suggested invoice' | $T8 %][% IF !prop.is_sales %] ([% 'AP' | $T8 %])[% END %]</th><th>[% 'Bank transaction' | $T8 %]</th></tr><tr><th>[% 'Amount' | $T8 %]</th><td>[% LxERP.format_amount(prop.amount, 2) %] ([% 'open' | $T8 %]: [% LxERP.format_amount(prop.open_amount, 2) %])</td><td>[% LxERP.format_amount(bt.amount, 2) %]</td></tr>[% IF prop.skonto_date %]<tr><th>[% 'Payment terms' | $T8 %]</th><td>[% LxERP.format_amount(prop.amount_less_skonto, 2) %] [% 'until' | $T8 %] [% HTML.escape(prop.skonto_date.to_kivitendo) %] ([% prop.percent_skonto * 100 %] %)</td><td></td></tr>[% END %]<tr><th>[% 'Customer/Vendor' | $T8 %]</th><td>[% HTML.escape(prop.customer.displayable_name) %][% HTML.escape(prop.vendor.displayable_name) %]</td><td>[% HTML.escape(bt.remote_name) %]</td></tr><tr><th>[% 'Invoice Date' | $T8 %]</th><td>[% HTML.escape(prop.transdate_as_date) %]</td><td>[% HTML.escape(bt.transdate_as_date) %] ([% HTML.escape(bt.transdate.utc_rd_days - prop.transdate.utc_rd_days) %])</td></tr><tr><th>[% 'Invoice Number' | $T8 %]</th><td>[% HTML.escape(prop.invnumber) %]</td><td>[% HTML.escape(bt.purpose) %]</td></tr></table>"
+            title="<table><tr><th></th><th>[% 'Suggested invoice' | $T8 %][% IF !prop.is_sales %] ([% 'AP' | $T8 %])[% END %]</th><th>[% 'Bank transaction' | $T8 %]</th></tr><tr><th>[% 'Amount' | $T8 %]</th><td>[% LxERP.format_amount(prop.amount, 2) %] ([% 'open' | $T8 %]: [% LxERP.format_amount(prop.open_amount, 2) %])</td><td>[% LxERP.format_amount(bt.absamount, 2) %]</td></tr>[% IF prop.skonto_date %]<tr><th>[% 'Payment terms' | $T8 %]</th><td>[% LxERP.format_amount(prop.amount_less_skonto, 2) %] [% 'until' | $T8 %] [% HTML.escape(prop.skonto_date.to_kivitendo) %] ([% prop.percent_skonto * 100 %] %)</td><td></td></tr>[% END %]<tr><th>[% 'Customer/Vendor' | $T8 %]</th><td>[% HTML.escape(prop.customer.displayable_name) %][% HTML.escape(prop.vendor.displayable_name) %]</td><td>[% HTML.escape(bt.remote_name) %]</td></tr><tr><th>[% 'Invoice Date' | $T8 %]</th><td>[% HTML.escape(prop.transdate_as_date) %]</td><td>[% HTML.escape(bt.transdate_as_date) %] ([% HTML.escape(bt.transdate.utc_rd_days - prop.transdate.utc_rd_days) %])</td></tr><tr><th>[% 'Invoice Number' | $T8 %]</th><td>[% HTML.escape(prop.invnumber) %]</td><td>[% HTML.escape(bt.purpose) %]</td></tr></table>"
               class="[% IF bt.agreement >= 5 %]green[% ELSIF bt.agreement < 5 and bt.agreement >= 3 %]orange[% ELSE %]red[% END %] tooltipster-html">&larr;[% HTML.escape(prop.invnumber)%]</a></div>
       [% END %]
      </td>
      <td align=right>[% bt.invoice_amount_as_number %]</td>
      <td>[% HTML.escape(bt.remote_name) %]</td>
      <td>[% HTML.escape(bt.purpose) %]</td>
+     <td>[% HTML.escape(bt.transactiontext) %]</td>
      <td>[% HTML.escape(bt.remote_account_number) %]</td>
      <td>[% HTML.escape(bt.remote_bank_code) %]</td>
      <td align=right>[% bt.valutadate_as_date %]</td>
     [%- END %]
   </tbody>
  </table>
+[% L.submit_tag('action_save_invoices', LxERP.t8('Save invoices')) %]
+
+</form>
index 42f387f..12054cf 100644 (file)
@@ -1,5 +1,12 @@
 [%- USE HTML -%][%- USE LxERP -%][%- USE L -%][%- USE T8 -%]
 
+<form method="post" id="list_form">
+[% L.hidden_tag('filter.bank_account', FORM.filter.bank_account) %]
+[% L.hidden_tag('filter.fromdate', FORM.filter.fromdate) %]
+[% L.hidden_tag('filter.todate',   FORM.filter.todate) %]
+[% L.hidden_tag('action', 'BankTransaction/dispatch') %]
+[% L.hidden_tag('ui_tab', ui_tab) %]
+
 <table>
   <thead>
     <tr class="listheading">
@@ -9,6 +16,7 @@
       <th>[% 'ID' | $T8 %]</th>
       <th>[% 'Transdate' | $T8 %]</th>
       <th>[% 'Amount' | $T8 %]</th>
+      <th>[% 'Skonto' | $T8 %]</th>
       <th>[% 'Purpose/Reference' | $T8 %]</th>
       <th>[% 'Customer/Vendor/Remote name' | $T8 %]</th>
     </tr>
     [% FOREACH proposal = PROPOSALS %]
       <tbody class="listrow">
         <tr>
-          <td rowspan=2 style="valign:center;">
+          <td rowspan=[% proposal.rowspan %] style="valign:center;">
             [% L.checkbox_tag('proposal_ids[]', checked=0, value=proposal.id) %]
           </td>
 
-          <td>[% 'Bank transaction' | $T8 %]</td>
+          <td>[% HTML.escape(proposal.transactiontext) %]</td>
           <td>[% proposal.id %]</td>
           <td>[% proposal.transdate_as_date %]</td>
-          <td>[% proposal.amount_as_number %]</td>
+          <td align="right">[% proposal.amount_as_number %]</td>
+          <td></td>
           <td>[% HTML.escape(proposal.purpose) %]</td>
           <td>[% HTML.escape(proposal.remote_name) %]</td>
         </tr>
       [% FOREACH proposed_invoice = proposal.proposals %]
         <tr>
 
+          <td></td>
           <td>[% 'Invoice' | $T8 %]</td>
           <td>[% proposed_invoice.id %]</td>
-          <td>[% proposed_invoice.transdate_as_date %]</td>
-          <td>[% proposed_invoice.amount_as_number %]</td>
+          <td>[% proposed_invoice.transdate_as_date %]
+              [% L.hidden_tag("invoice_ids." _ proposal.id _ "[]", proposed_invoice.id) %]</td>
+          <td align="right">[% proposed_invoice.realamount %]</td>
+          <td>[% proposed_invoice.skonto_type | $T8 %]
+              [% L.hidden_tag("invoice_skontos." _ proposal.id _ "[]", proposed_invoice.skonto_type) %]</td>
           <td>[% proposed_invoice.link %]</td>
           <td>[% HTML.escape(proposed_invoice.customer.name) %][% HTML.escape(proposed_invoice.vendor.name) %]</td>
         </tr>
-            [% L.hidden_tag("proposed_invoice_" _ proposal.id, proposed_invoice.id) %]
-      [% END %]
+        [% END %]
+        <tr><td style="height:10px"></td></tr>
       </tbody>
     [% END %]
   [% END %]
 </table>
+[% L.submit_tag('action_save_proposals', LxERP.t8('Save proposals')) %]
+
+</form>