Freies Fälligkeitsdatum: richtige Variable an Berechnungsroutine weiterreichen
[kivitendo-erp.git] / bin / mozilla / is.pl
index e1e70ec..9af6b21 100644 (file)
@@ -39,12 +39,14 @@ use Data::Dumper;
 use DateTime;
 use List::MoreUtils qw(uniq);
 use List::Util qw(max sum);
+use List::UtilsBy qw(sort_by);
+use English qw(-no_match_vars);
 
 use SL::DB::Default;
 use SL::DB::Customer;
+use SL::DB::PaymentTerm;
 
 require "bin/mozilla/io.pl";
-require "bin/mozilla/invoice_io.pl";
 require "bin/mozilla/arap.pl";
 require "bin/mozilla/drafts.pl";
 
@@ -64,6 +66,8 @@ sub add {
 
   return $main::lxdebug->leave_sub() if (load_draft_maybe());
 
+  $form->{show_details} = $::myconfig{show_form_details};
+
   if ($form->{type} eq "credit_note") {
     $form->{title} = $locale->text('Add Credit Note');
 
@@ -93,11 +97,11 @@ sub edit {
 
   $main::auth->assert('invoice_edit');
 
+  $form->{show_details}                = $::myconfig{show_form_details};
   $form->{taxincluded_changed_by_user} = 1;
 
   # show history button
   $form->{javascript} = qq|<script type="text/javascript" src="js/show_history.js"></script>|;
-  #/show hhistory button
 
   my ($language_id, $printer_id);
   if ($form->{print_and_post}) {
@@ -138,8 +142,6 @@ sub invoice_links {
   $form->{vc} = 'customer';
 
   # create links
-  $form->{webdav}   = $::instance_conf->get_webdav;
-
   $form->create_links("AR", \%myconfig, "customer");
 
   if ($form->{all_customer}) {
@@ -171,7 +173,7 @@ sub invoice_links {
   $form->restore_vars(qw(salesman_id)) if $editing;
 
 
-  # build vendor/customer drop down comatibility... don't ask
+  # build vendor/customer drop down compatibility... don't ask
   if (@{ $form->{"all_customer"} }) {
     $form->{"selectcustomer"} = 1;
     $form->{customer}         = qq|$form->{customer}--$form->{"customer_id"}|;
@@ -290,6 +292,10 @@ sub form_header {
   my %TMPL_VAR = ();
   my @custom_hiddens;
 
+  if ($form->{id}) {
+    require SL::DB::Invoice;
+    $TMPL_VAR{invoice_obj} = SL::DB::Invoice->new(id => $form->{id})->load;
+  }
   $form->{employee_id} = $form->{old_employee_id} if $form->{old_employee_id};
   $form->{salesman_id} = $form->{old_salesman_id} if $form->{old_salesman_id};
 
@@ -319,6 +325,7 @@ sub form_header {
     ]);
 
   $TMPL_VAR{ALL_PROJECTS}          = SL::DB::Manager::Project->get_all_sorted(query => \@conditions);
+  $form->{ALL_PROJECTS}            = $TMPL_VAR{ALL_PROJECTS}; # make projects available for second row drop-down in io.pl
   $TMPL_VAR{ALL_EMPLOYEES}         = SL::DB::Manager::Employee->get_all_sorted(query => [ or => [ id => $::form->{employee_id},  deleted => 0 ] ]);
   $TMPL_VAR{ALL_SALESMEN}          = SL::DB::Manager::Employee->get_all_sorted(query => [ or => [ id => $::form->{salesman_id},  deleted => 0 ] ]);
   $TMPL_VAR{ALL_SHIPTO}            = SL::DB::Manager::Shipto->get_all_sorted(query => [
@@ -377,16 +384,19 @@ sub form_header {
   $TMPL_VAR{HIDDENS} = [qw(
     id action type media format queued printed emailed title vc discount
     title creditlimit creditremaining tradediscount business closedto locked shipped storno storno_id
-    max_dunning_level dunning_amount
-    shiptoname shiptostreet shiptozipcode shiptocity shiptocountry  shiptocontact shiptophone shiptofax
+    max_dunning_level dunning_amount dunning_description
+    shiptoname shiptostreet shiptozipcode shiptocity shiptocountry shiptogln shiptocontact shiptophone shiptofax
     shiptoemail shiptodepartment_1 shiptodepartment_2  shiptocp_gender message email subject cc bcc taxaccounts cursor_fokus
-    convert_from_do_ids convert_from_oe_ids convert_from_ar_ids
+    convert_from_do_ids convert_from_oe_ids convert_from_ar_ids useasnew
     invoice_id
     show_details
   ), @custom_hiddens,
   map { $_.'_rate', $_.'_description', $_.'_taxnumber' } split / /, $form->{taxaccounts}];
 
-  $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.SalesPurchase ckeditor/ckeditor ckeditor/adapters/jquery kivi.io autocomplete_customer autocomplete_part));
+  $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.SalesPurchase ckeditor/ckeditor ckeditor/adapters/jquery kivi.io autocomplete_customer autocomplete_part client_js));
+
+  $TMPL_VAR{payment_terms_obj} = get_payment_terms_for_invoice();
+  $form->{duedate}             = $TMPL_VAR{payment_terms_obj}->calc_date(reference_date => $form->{invdate}, due_date => $form->{duedate})->to_kivitendo if $TMPL_VAR{payment_terms_obj};
 
   $form->header();
 
@@ -395,6 +405,25 @@ sub form_header {
   $main::lxdebug->leave_sub();
 }
 
+sub _sort_payments {
+  my @fields   = qw(acc_trans_id gldate datepaid source memo paid AR_paid);
+  my @payments =
+    grep { $_->{paid} != 0 }
+    map  {
+      my $idx = $_;
+      +{ map { ($_ => delete($::form->{"${_}_${idx}"})) } @fields }
+    } (1..$::form->{paidaccounts});
+
+  @payments = sort_by { DateTime->from_kivitendo($_->{datepaid}) } @payments;
+
+  $::form->{paidaccounts} = max scalar(@payments), 1;
+
+  foreach my $idx (1 .. scalar(@payments)) {
+    my $payment = $payments[$idx - 1];
+    $::form->{"${_}_${idx}"} = $payment->{$_} for @fields;
+  }
+}
+
 sub form_footer {
   $main::lxdebug->enter_sub();
 
@@ -434,6 +463,11 @@ sub form_footer {
     }
   }
 
+  $form->{rounding} = $form->round_amount(
+    $form->round_amount($form->{invtotal}, 2, 1) - $form->round_amount($form->{invtotal}, 2), 2
+  );
+  $form->{invtotal} = $form->round_amount( $form->{invtotal}, 2, 1 );
+
   # follow ups
   if ($form->{id}) {
     $form->{follow_ups}            = FU->follow_ups('trans_id' => $form->{id}) || [];
@@ -441,6 +475,8 @@ sub form_footer {
   }
 
   # payments
+  _sort_payments();
+
   my $totalpaid = 0;
   $form->{paidaccounts}++ if ($form->{"paid_$form->{paidaccounts}"});
   $form->{paid_indices} = [ 1 .. $form->{paidaccounts} ];
@@ -482,6 +518,7 @@ sub form_footer {
     show_delete         => ($::instance_conf->get_is_changeable == 2)
                              ? ($form->current_date(\%myconfig) eq $form->{gldate})
                              : ($::instance_conf->get_is_changeable == 1),
+    today               => DateTime->today,
   });
 ##print $form->parse_html_template('is/_payments'); # parser
 ##print $form->parse_html_template('webdav/_list'); # parser
@@ -553,11 +590,8 @@ sub update {
 
     my $rows = scalar @{ $form->{item_list} };
 
-    # Falls kein Kundenrabatt vorhanden ist, den aktuellen Rabatt nicht mit 0% überschreiben,
-    # da hier der Anwender schon manual einen Wert eingetragen haben könnte (analog zu qty) Bugfix: 1412
-    if ($form->{customer_discount}){
-      $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{customer_discount} * 100);
-    }
+    $form->{"discount_$i"}   = $form->parse_amount(\%myconfig, $form->{"discount_$i"}) / 100.0;
+    $form->{"discount_$i"} ||= $form->{customer_discount};
 
     if ($rows) {
       $form->{"qty_$i"} = $form->parse_amount(\%myconfig, $form->{"qty_$i"});
@@ -567,7 +601,7 @@ sub update {
 
       if ($rows > 1) {
 
-        select_item(mode => 'IS');
+        select_item(mode => 'IS', pre_entered_qty => $form->{"qty_$i"});
         ::end_of_request();
 
       } else {
@@ -608,7 +642,7 @@ sub update {
 
         $form->{"listprice_$i"} /= $exchangerate;
 
-        my $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * (1 - $form->{"discount_$i"} / 100);
+        my $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * (1 - $form->{"discount_$i"});
         map { $form->{"${_}_base"} = 0 }                                 split / /, $form->{taxaccounts};
         map { $form->{"${_}_base"} += $amount }                          split / /, $form->{"taxaccounts_$i"};
         map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
@@ -617,7 +651,8 @@ sub update {
 
         map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, $decimalplaces) } qw(sellprice lastcost);
 
-        $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+        $form->{"qty_$i"}      = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+        $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"discount_$i"} * 100.0);
       }
 
       &display_form;
@@ -652,6 +687,7 @@ sub post_payment {
 
   $main::auth->assert('invoice_edit');
 
+  $form->mtime_ischanged('ar') ;
   my $invdate = $form->datetonum($form->{invdate}, \%myconfig);
 
   $form->{defaultcurrency} = $form->get_default_currency(\%myconfig);
@@ -686,10 +722,15 @@ sub post_payment {
   ($form->{AR})      = split /--/, $form->{AR};
   ($form->{AR_paid}) = split /--/, $form->{AR_paid};
   relink_accounts();
-  $form->redirect($locale->text('Payment posted!'))
-      if (IS->post_payment(\%myconfig, \%$form));
-    $form->error($locale->text('Cannot post payment!'));
-
+  if ( IS->post_payment(\%myconfig, \%$form) ) {
+    $form->{snumbers}  = qq|invnumber_| . $form->{invnumber};
+    $form->{what_done} = 'invoice';
+    $form->{addition}  = "PAYMENT POSTED";
+    $form->save_history;
+    $form->redirect($locale->text('Payment posted!'))
+  } else {
+   $form->error($locale->text('Cannot post payment!'));
+  };
 
   $main::lxdebug->leave_sub();
 }
@@ -702,6 +743,7 @@ sub post {
   my $locale   = $main::locale;
 
   $main::auth->assert('invoice_edit');
+  $form->mtime_ischanged('ar');
 
   $form->{defaultcurrency} = $form->get_default_currency(\%myconfig);
   $form->isblank("invdate",  $locale->text('Invoice Date missing!'));
@@ -778,15 +820,54 @@ sub post {
   }
 
   relink_accounts();
-  $form->error($locale->text('Cannot post invoice!'))
-    unless IS->post_invoice(\%myconfig, \%$form);
+
+  my $terms        = get_payment_terms_for_invoice();
+  $form->{duedate} = $terms->calc_date(reference_date => $form->{invdate}, due_date => $form->{due_due})->to_kivitendo if $terms;
+
+  # If transfer_out is requested, get rose db handle and do post and
+  # transfer out in one transaction. Otherwise just post the invoice.
+  if ($::instance_conf->get_is_transfer_out && $form->{type} ne 'credit_note' && !$form->{storno}) {
+    require SL::DB::Inventory;
+    my $rose_db = SL::DB::Inventory->new->db;
+    my @errors;
+
+    if (!$rose_db->with_transaction(sub {
+      if (!eval {
+        if (!IS->post_invoice(\%myconfig, \%$form, $rose_db->dbh)) {
+          push @errors, $locale->text('Cannot post invoice!');
+          die 'posting error';
+        }
+        my $err = IS->transfer_out(\%$form, $rose_db->dbh);
+        if (@{ $err }) {
+          push @errors, @{ $err };
+          die 'transfer error';
+        }
+
+        1;
+      }) {
+        push @errors, $EVAL_ERROR;
+        die 'transaction error';
+      }
+
+      1;
+    })) {
+      push @errors, $rose_db->error;
+      $form->error($locale->text('Cannot post invoice and/or transfer out! Error message:') . "\n" . join("\n", @errors));
+    }
+  } else {
+    if (!IS->post_invoice(\%myconfig, \%$form)) {
+      $form->error($locale->text('Cannot post invoice!'));
+    }
+  }
+
   remove_draft() if $form->{remove_draft};
 
   if(!exists $form->{addition}) {
-    $form->{snumbers} =  'invnumber' .'_'. $form->{invnumber}; # ($form->{type} eq 'credit_note' ? 'cnnumber' : 'invnumber') .'_'. $form->{invnumber};
-    $form->{addition} = $form->{print_and_post} ? "PRINTED AND POSTED" :
-                        $form->{storno}         ? "STORNO"             :
-                                                  "POSTED";
+    $form->{snumbers}  =  'invnumber' .'_'. $form->{invnumber}; # ($form->{type} eq 'credit_note' ? 'cnnumber' : 'invnumber') .'_'. $form->{invnumber};
+    $form->{what_done} = 'invoice';
+    $form->{addition}  = $form->{print_and_post} ? "PRINTED AND POSTED" :
+                         $form->{storno}         ? "STORNO"             :
+                                                   "POSTED";
     $form->save_history;
   }
 
@@ -794,7 +875,7 @@ sub post {
     $form->{action} = 'edit';
     $form->{script} = 'is.pl';
     $form->{saved_message} = $form->{label} . " $form->{invnumber} " . $locale->text('posted!');
-    $form->{callback} = build_std_url(qw(action edit id saved_message));
+    $form->{callback} = build_std_url(qw(action edit id callback saved_message));
     $form->redirect;
   }
 
@@ -808,7 +889,7 @@ sub print_and_post {
 
   $main::auth->assert('invoice_edit');
 
-  my $old_form                    = new Form;
+  my $old_form                    = Form->new;
   $form->{no_redirect_after_post} = 1;
   $form->{print_and_post}         = 1;
   &post();
@@ -830,12 +911,15 @@ sub use_as_new {
   $form->{rowcount}--;
   $form->{paidaccounts} = 1;
   $form->{invdate}      = $form->current_date(\%myconfig);
-  $form->{duedate}      = $form->get_duedate(\%myconfig, $form->{invdate}) || $form->{invdate};
+  my $terms             = get_payment_terms_for_invoice();
+  $form->{duedate}      = $terms ? $terms->calc_date(reference_date => $form->{invdate})->to_kivitendo : $form->{invdate};
   $form->{employee_id}  = SL::DB::Manager::Employee->current->id;
   $form->{forex}        = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy');
   $form->{exchangerate} = $form->{forex} if $form->{forex};
-  delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
 
+  $form->{"converted_from_invoice_id_$_"} = delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
+
+  $form->{useasnew} = 1;
   &display_form;
 
   $main::lxdebug->leave_sub();
@@ -861,6 +945,12 @@ sub storno {
     $form->error($locale->text('Cannot storno invoice for a closed period!'));
   }
 
+  # save the history of invoice being stornoed
+  $form->{snumbers}  = qq|invnumber_| . $form->{invnumber};
+  $form->{what_done} = 'invoice';
+  $form->{addition}  = "STORNO";
+  $form->save_history;
+
   map({ my $key = $_; delete($form->{$key}) unless (grep({ $key eq $_ } qw(id login password type))); } keys(%{ $form }));
 
   invoice_links();
@@ -892,7 +982,7 @@ sub preview {
   $main::auth->assert('invoice_edit');
 
   $form->{preview} = 1;
-  my $old_form = new Form;
+  my $old_form = Form->new;
   for (keys %$form) { $old_form->{$_} = $form->{$_} }
 
   &print_form($old_form);
@@ -978,13 +1068,8 @@ sub credit_note {
 #  map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
 #    qw(creditlimit creditremaining);
 
-  for my $i (1 .. $form->{rowcount}) {
-    for (qw(listprice)) {
-      $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"}) if $form->{"${_}_${i}"};
-    }
-  }
-  # set new persistent ids for credit note
-  delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
+  # set new persistent ids for credit note and link previous invoice id
+  $form->{"converted_from_invoice_id_$_"} = delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
 
   my $currency = $form->{currency};
   &invoice_links;
@@ -1015,6 +1100,27 @@ sub credit_note {
   $main::lxdebug->leave_sub();
 }
 
+sub display_form {
+  $::lxdebug->enter_sub;
+
+  $::auth->assert('invoice_edit');
+
+  relink_accounts();
+
+  my $new_rowcount = $::form->{"rowcount"} * 1 + 1;
+  $::form->{"project_id_${new_rowcount}"} = $::form->{"globalproject_id"};
+
+  $::form->language_payment(\%::myconfig);
+
+  Common::webdav_folder($::form);
+
+  form_header();
+  display_row(++$::form->{rowcount});
+  form_footer();
+
+  $::lxdebug->leave_sub;
+}
+
 sub yes {
   $main::lxdebug->enter_sub();
 
@@ -1027,8 +1133,9 @@ sub yes {
   if (IS->delete_invoice(\%myconfig, \%$form)) {
     # saving the history
     if(!exists $form->{addition}) {
-      $form->{snumbers} = 'invnumber' .'_'. $form->{invnumber}; # ($form->{type} eq 'credit_note' ? 'cnnumber' : 'invnumber') .'_'. $form->{invnumber};
-      $form->{addition} = "DELETED";
+      $form->{snumbers}  = 'invnumber' .'_'. $form->{invnumber}; # ($form->{type} eq 'credit_note' ? 'cnnumber' : 'invnumber') .'_'. $form->{invnumber};
+      $form->{what_done} = 'invoice';
+      $form->{addition}  = "DELETED";
       $form->save_history;
     }
     # /saving the history