Payment Kosmetik/Konvention
[kivitendo-erp.git] / SL / DB / Helper / Payment.pm
index 17b24f8..2f67945 100644 (file)
@@ -30,7 +30,7 @@ sub pay_invoice {
 
   my $is_sales = ref($self) eq 'SL::DB::Invoice';
   my $mult = $is_sales ? 1 : -1;  # multiplier for getting the right sign depending on ar/ap
-
+  my @new_acc_ids;
   my $paid_amount = 0; # the amount that will be later added to $self->paid, should be in default currency
 
   # default values if not set
@@ -39,6 +39,10 @@ sub pay_invoice {
 
   # check for required parameters
   Common::check_params(\%params, qw(chart_id transdate));
+  if ( $params{'payment_type'} eq 'without_skonto' && abs($params{'amount'}) < 0) {
+    croak "invalid amount for payment_type 'without_skonto': $params{'amount'}\n";
+  }
+
 
   my $transdate_obj;
   if (ref($params{transdate} eq 'DateTime')) {
@@ -84,11 +88,6 @@ sub pay_invoice {
     $exchangerate = 1;
   };
 
-  # input checks:
-  if ( $params{'payment_type'} eq 'without_skonto' ) {
-    croak "invalid amount for payment_type 'without_skonto': $params{'amount'}\n" unless abs($params{'amount'}) > 0;
-  };
-
   # options with_skonto_pt and difference_as_skonto don't require the parameter
   # amount, but if amount is passed, make sure it matches the expected value
   if ( $params{'payment_type'} eq 'difference_as_skonto' ) {
@@ -123,8 +122,8 @@ sub pay_invoice {
     my $new_acc_trans;
 
     # all three payment type create 1 AR/AP booking (the paid part)
-    # difference_as_skonto creates n skonto bookings (1 for each tax type)
-    # with_skonto_pt creates 1 bank booking and n skonto bookings (1 for each tax type)
+    # difference_as_skonto creates n skonto bookings (1 for each buchungsgruppe type)
+    # with_skonto_pt creates 1 bank booking and n skonto bookings (1 for each buchungsgruppe type)
     # without_skonto creates 1 bank booking
 
     # as long as there is no automatic tax, payments are always booked with
@@ -158,6 +157,7 @@ sub pay_invoice {
                                                    tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
       $new_acc_trans->save;
 
+      push @new_acc_ids, $new_acc_trans->acc_trans_id;
       # deal with fxtransaction
       if ( $self->currency_id != $::instance_conf->get_currency_id ) {
         my $fxamount = _round($amount - ($amount * $exchangerate));
@@ -172,6 +172,7 @@ sub pay_invoice {
                                                      fx_transaction => 1,
                                                      tax_id         => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
         $new_acc_trans->save;
+        push @new_acc_ids, $new_acc_trans->acc_trans_id;
         # if invoice exchangerate differs from exchangerate of payment
         # deal with fxloss and fxamount
         if ($self->exchangerate and $self->exchangerate != 1 and $self->exchangerate != $exchangerate) {
@@ -192,10 +193,11 @@ sub pay_invoice {
                                                        fx_transaction => 0,
                                                        tax_id         => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
           $new_acc_trans->save;
+          push @new_acc_ids, $new_acc_trans->acc_trans_id;
 
-        };
-      };
-    };
+        }
+      }
+    }
 
     if ( $params{payment_type} eq 'difference_as_skonto' or $params{payment_type} eq 'with_skonto_pt' ) {
 
@@ -232,6 +234,7 @@ sub pay_invoice {
 
         # the acc_trans entries are saved individually, not added to $self and then saved all at once
         $new_acc_trans->save;
+        push @new_acc_ids, $new_acc_trans->acc_trans_id;
 
         $reference_amount -= abs($amount);
         $paid_amount      += -1 * $amount * $exchangerate;
@@ -240,8 +243,7 @@ sub pay_invoice {
       if ( $params{payment_type} eq 'difference_as_skonto' ) {
           die "difference_as_skonto calculated incorrectly, sum of calculated payments doesn't add up to open amount $total_open_amount, reference_amount = $reference_amount\n" unless _round($reference_amount) == 0;
       }
-
-    };
+    }
 
     my $arap_amount = 0;
 
@@ -254,7 +256,7 @@ sub pay_invoice {
       # with_skonto_pt for completely unpaid invoices we just use the value
       # from the invoice
       $arap_amount = $total_open_amount;
-    };
+    }
 
     # regardless of payment_type there is always only exactly one arap booking
     # TODO: compare $arap_amount to running total
@@ -267,6 +269,7 @@ sub pay_invoice {
                                                   taxkey     => 0,
                                                   tax_id     => SL::DB::Manager::Tax->find_by(taxkey => 0)->id);
     $arap_booking->save;
+    push @new_acc_ids, $arap_booking->acc_trans_id;
 
     $fx_gain_loss_amount *= -1 if $self->is_sales;
     $self->paid($self->paid + _round($paid_amount) + $fx_gain_loss_amount) if $paid_amount;
@@ -309,9 +312,8 @@ sub pay_invoice {
     1;
 
   }) || die t8('error while paying invoice #1 : ', $self->invnumber) . $db->error . "\n";
-
-  return 1;
-};
+  return wantarray ? @new_acc_ids : 1;
+}
 
 sub skonto_date {
 
@@ -443,8 +445,6 @@ sub amount_less_skonto {
   # the result is rounded so we can directly compare it with the user input
   my $self = shift;
 
-  my $is_sales = ref($self) eq 'SL::DB::Invoice';
-
   my $percent_skonto = $self->percent_skonto || 0;
 
   return _round($self->amount - ( $self->amount * $percent_skonto) );
@@ -629,24 +629,20 @@ sub valid_skonto_amount {
 sub get_payment_select_options_for_bank_transaction {
   my ($self, $bt_id, %params) = @_;
 
-  my $bt = SL::DB::Manager::BankTransaction->find_by( id => $bt_id );
-  croak ("Need bt_id to get a valid bank transaction") unless $bt;
+  # no skonto date  -> no select option
+  return { payment_type => 'without_skonto', display => t8('without skonto') , selected => 1 } unless $self->skonto_date;
 
-  # user may overpay invoices and if not, this case should better be handled elsewhere
-  #my $open_amount = $self->open_amount;
-  #croak ("Need an open invoice") unless $open_amount;
+  my $bt = SL::DB::BankTransaction->new(id => $bt_id)->load;
 
   my @options;
 
-    if ($self->skonto_date && $self->within_skonto_period($bt->transdate)) {
-      push(@options, { payment_type => 'without_skonto', display => t8('without skonto') });
-      push(@options, { payment_type => 'with_skonto_pt', display => t8('with skonto acc. to pt'), selected => 1 });
-    } else {
-      push(@options, { payment_type => 'without_skonto', display => t8('without skonto') , selected => 1 });
-      push(@options, { payment_type => 'with_skonto_pt', display => t8('with skonto acc. to pt')});
-    }
+  if ($self->skonto_date && $self->within_skonto_period($bt->transdate)) {
+    push(@options, { payment_type => 'without_skonto', display => t8('without skonto') });
+    push(@options, { payment_type => 'with_skonto_pt', display => t8('with skonto acc. to pt'), selected => 1 });
+  } else {
+    push(@options, { payment_type => 'without_skonto', display => t8('without skonto') , selected => 1 });
+    push(@options, { payment_type => 'with_skonto_pt', display => t8('with skonto acc. to pt')});
   }
-
   return @options;
 }
 
@@ -759,6 +755,14 @@ Create a payment booking for an existing invoice object (type ar/ap/is/ir) via
 a configured bank account.
 
 This function deals with all the acc_trans entries and also updates paid and datepaid.
+The params C<transdate> and C<chart_id> are mandantory.
+If the default payment ('without_skonto') is used the param amount is also
+mandantory.
+
+Transdate can either be a date object or a date string.
+Chart_id is the id of the payment booking chart.
+Amount is either a postive or negative number, but never 0.
+
 
 Example:
 
@@ -848,6 +852,8 @@ If no amount is given the whole open amout is paid.
 If neither currency or currency_id are given as params, the currency of the
 invoice is assumed to be the payment currency.
 
+If successful the return value will be 1 in scalar context or in list context
+the two ids (acc_trans_id) of the newly created bookings.
 =item C<reference_account>
 
 Returns a chart object which is the chart of the invoice with link AR or AP.
@@ -1062,10 +1068,14 @@ might always want to pay as late as possible.
 Make suggestion for a skonto payment type by returning an HTML blob of the options
 of a HTML drop-down select with the most likely option preselected.
 
-This is a helper function for BankTransaction/ajax_payment_suggestion.
+This is a helper function for BankTransaction/ajax_payment_suggestion and
+template/webpages/bank_transactions/invoices.html
 
 We are working with an existing payment, so difference_as_skonto never makes sense.
 
+If skonto is not possible (skonto_date does not exists) simply return
+the single 'no skonto' option as a visual hint.
+
 If skonto is possible (skonto_date exists), add two possibilities:
 without_skonto and with_skonto_pt if payment date is within skonto_date,
 preselect with_skonto_pt, otherwise preselect without skonto.