Factur-X/ZUGFeRD: in »Factur-X/ZUGFeRD« umbenannt
[kivitendo-erp.git] / bin / mozilla / ap.pl
index 49f6f7a..2fe8041 100644 (file)
@@ -47,6 +47,7 @@ use SL::DB::BankTransactionAccTrans;
 use SL::DB::Chart;
 use SL::DB::Currency;
 use SL::DB::Default;
+use SL::DB::Order;
 use SL::DB::PurchaseInvoice;
 use SL::DB::RecordTemplate;
 use SL::DB::Tax;
@@ -412,23 +413,9 @@ sub form_header {
 
   $form->{creditremaining_plus} = ($form->{creditremaining} =~ /-/) ? "0" : "1";
 
-  my @old_project_ids = ();
-  map(
-    {
-      if ($form->{"project_id_$_"}) {
-        push(@old_project_ids, $form->{"project_id_$_"});
-      }
-    }
-    (1..$form->{"rowcount"})
-  );
-
-  $form->get_lists("projects"  => { "key"       => "ALL_PROJECTS",
-                                    "all"       => 0,
-                                    "old_id"    => \@old_project_ids },
-                   "charts"    => { "key"       => "ALL_CHARTS",
+  $form->get_lists("charts"    => { "key"       => "ALL_CHARTS",
                                     "transdate" => $form->{transdate} },
-                   "taxcharts" => { "key"       => "ALL_TAXCHARTS",
-                                    "module"    => "AP" },);
+                  );
 
   map(
     { $_->{link_split} = [ split(/:/, $_->{link}) ]; }
@@ -437,10 +424,7 @@ sub form_header {
 
   $form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all_sorted;
 
-  my %project_labels = ();
-  foreach my $item (@{ $form->{"ALL_PROJECTS"} }) {
-    $project_labels{$item->{id}} = $item->{projectnumber};
-  }
+  my %project_labels = map { $_->id => $_->projectnumber }  @{ SL::DB::Manager::Project->get_all };
 
   my %charts;
   my $default_ap_amount_chart_id;
@@ -459,10 +443,7 @@ sub form_header {
   my $follow_up_vc         = $form->{vendor_id} ? SL::DB::Vendor->load_cached($form->{vendor_id})->name : '';
   my $follow_up_trans_info =  "$form->{invnumber} ($follow_up_vc)";
 
-  $::request->layout->add_javascripts("autocomplete_chart.js", "show_vc_details.js", "show_history.js", "follow_up.js", "kivi.Draft.js", "kivi.GL.js", "kivi.RecordTemplate.js", "kivi.File.js", "kivi.AP.js", "kivi.CustomerVendor.js", "kivi.Validator.js");
-  my $transdate = $::form->{transdate} ? DateTime->from_kivitendo($::form->{transdate}) : DateTime->today_local;
-  my $first_taxchart;
-
+  $::request->layout->add_javascripts("autocomplete_chart.js", "show_vc_details.js", "show_history.js", "follow_up.js", "kivi.Draft.js", "kivi.GL.js", "kivi.RecordTemplate.js", "kivi.File.js", "kivi.AP.js", "kivi.CustomerVendor.js", "kivi.Validator.js", "autocomplete_project.js");
   # $form->{totalpaid} is used by the action bar setup to determine
   # whether or not canceling is allowed. Therefore it must be
   # calculated prior to the action bar setup.
@@ -471,6 +452,12 @@ sub form_header {
   setup_ap_display_form_action_bar();
 
   $form->header();
+  # get the correct date for tax
+  my $transdate    = $::form->{transdate}    ? DateTime->from_kivitendo($::form->{transdate})    : DateTime->today_local;
+  my $deliverydate = $::form->{deliverydate} ? DateTime->from_kivitendo($::form->{deliverydate}) : undef;
+  my $taxdate      = $deliverydate ? $deliverydate : $transdate;
+  # helper for loop
+  my $first_taxchart;
 
   for my $i (1 .. $form->{rowcount}) {
 
@@ -479,9 +466,13 @@ sub form_header {
     $form->{"tax_$i"} = $form->format_amount(\%myconfig, $form->{"tax_$i"}, 2);
 
     my ($default_taxchart, $taxchart_to_use);
+    my $used_tax_id;
+    if ( $form->{"taxchart_$i"} ) {
+      ($used_tax_id) = split(/--/, $form->{"taxchart_$i"});
+    }
     my $amount_chart_id = $form->{"AP_amount_chart_id_$i"} || $default_ap_amount_chart_id;
-    my @taxcharts       = GL->get_active_taxes_for_chart($amount_chart_id, $transdate);
 
+    my @taxcharts       = GL->get_active_taxes_for_chart($amount_chart_id, $taxdate, $used_tax_id);
     foreach my $item (@taxcharts) {
       my $key             = $item->id . "--" . $item->rate;
       $first_taxchart   //= $item;
@@ -500,7 +491,7 @@ sub form_header {
     my $item = shift;
     return [
       $item->{id} .'--'. $item->{rate},
-      $item->{taxdescription} .' '. ($item->{rate} * 100) .' %',
+      $item->{taxkey} . ' - ' . $item->{taxdescription} .' '. ($item->{rate} * 100) .' %',
     ];
   };
 
@@ -636,7 +627,7 @@ sub update {
   map { $form->{$_} = $form->parse_amount(\%myconfig, $form->{$_}) }
     qw(exchangerate creditlimit creditremaining);
 
-  my @flds  = qw(amount AP_amount projectnumber oldprojectnumber project_id taxchart);
+  my @flds  = qw(amount AP_amount_chart_id projectnumber oldprojectnumber project_id taxchart tax);
   my $count = 0;
   my (@a, $j, $totaltax);
   for my $i (1 .. $form->{rowcount}) {
@@ -649,7 +640,6 @@ sub update {
       # calculate tax exactly the same way as AP in post_transaction via form->calculate_tax
       my $tmpnetamount;
       ($tmpnetamount,$form->{"tax_$i"}) = $form->calculate_tax($form->{"amount_$i"},$rate,$form->{taxincluded},2);
-
       $totaltax += $form->{"tax_$i"};
       map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds;
       $count++;
@@ -899,7 +889,7 @@ sub use_as_new {
 
   $main::auth->assert('ap_transactions');
 
-  map { delete $form->{$_} } qw(printed emailed queued invnumber deliverydate id datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno);
+  map { delete $form->{$_} } qw(printed emailed queued invnumber deliverydate id datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno convert_from_oe_id);
   $form->{paidaccounts} = 1;
   $form->{rowcount}--;
 
@@ -947,8 +937,6 @@ sub search {
 
   $form->{title} = $locale->text('Vendor Invoices & AP Transactions');
 
-  $form->get_lists(projects => { "key" => "ALL_PROJECTS", "all" => 1 });
-
   $::form->{ALL_DEPARTMENTS} = SL::DB::Manager::Department->get_all_sorted;
   # constants and subs for template
   $form->{vc_keys}   = sub { "$_[0]->{name}--$_[0]->{id}" };
@@ -1001,12 +989,12 @@ sub ap_transactions {
 
   my @columns =
     qw(transdate id type invnumber ordnumber name netamount tax amount paid datepaid
-       due duedate transaction_description notes employee globalprojectnumber
+       due duedate transaction_description notes employee globalprojectnumber department
        vendornumber country ustid taxzone payment_terms charts direct_debit);
 
   my @hidden_variables = map { "l_${_}" } @columns;
   push @hidden_variables, "l_subtotal", qw(open closed vendor invnumber ordnumber transaction_description notes project_id transdatefrom transdateto
-                                           parts_partnumber parts_description);
+                                           parts_partnumber parts_description department_id);
 
   my $href = build_std_url('action=ap_transactions', grep { $form->{$_} } @hidden_variables);
 
@@ -1028,6 +1016,7 @@ sub ap_transactions {
     'notes'                   => { 'text' => $locale->text('Notes'), },
     'employee'                => { 'text' => $locale->text('Employee'), },
     'globalprojectnumber'     => { 'text' => $locale->text('Document Project Number'), },
+    'department'              => { 'text' => $locale->text('Department'), },
     'vendornumber'            => { 'text' => $locale->text('Vendor Number'), },
     'country'                 => { 'text' => $locale->text('Country'), },
     'ustid'                   => { 'text' => $locale->text('USt-IdNr.'), },
@@ -1037,7 +1026,7 @@ sub ap_transactions {
     'direct_debit'            => { 'text' => $locale->text('direct debit'), },
   );
 
-  foreach my $name (qw(id transdate duedate invnumber ordnumber name datepaid employee shippingpoint shipvia transaction_description direct_debit)) {
+  foreach my $name (qw(id transdate duedate invnumber ordnumber name datepaid employee shippingpoint shipvia transaction_description direct_debit department)) {
     my $sortdir                 = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir};
     $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir";
   }
@@ -1054,10 +1043,13 @@ sub ap_transactions {
 
   $report->set_sort_indicator($form->{sort}, $form->{sortdir});
 
+  my $department_description;
+  $department_description = SL::DB::Manager::Department->find_by(id => $form->{department_id})->description if $form->{department_id};
+
   my @options;
   push @options, $locale->text('Vendor')                  . " : $form->{vendor}"                         if ($form->{vendor});
   push @options, $locale->text('Contact Person')          . " : $form->{cp_name}"                        if ($form->{cp_name});
-  push @options, $locale->text('Department')              . " : $form->{department}"                     if ($form->{department});
+  push @options, $locale->text('Department')              . " : $department_description"                 if ($form->{department_id});
   push @options, $locale->text('Invoice Number')          . " : $form->{invnumber}"                      if ($form->{invnumber});
   push @options, $locale->text('Order Number')            . " : $form->{ordnumber}"                      if ($form->{ordnumber});
   push @options, $locale->text('Notes')                   . " : $form->{notes}"                          if ($form->{notes});
@@ -1183,6 +1175,74 @@ sub storno {
   $main::lxdebug->leave_sub();
 }
 
+sub add_from_purchase_order {
+  $main::auth->assert('ap_transactions');
+
+  return if !$::form->{id};
+
+  my $order_id = delete $::form->{id};
+  my $order    = SL::DB::Order->new(id => $order_id)->load(with => [ 'vendor', 'currency', 'payment_terms' ]);
+
+  return if $order->type ne 'purchase_order';
+
+  my $today                     = DateTime->today_local;
+  $::form->{title}              = "Add";
+  $::form->{vc}                 = 'vendor';
+  $::form->{vendor_id}          = $order->customervendor->id;
+  $::form->{vendor}             = $order->vendor->name;
+  $::form->{convert_from_oe_id} = $order->id;
+  $::form->{globalproject_id}   = $order->globalproject_id;
+  $::form->{ordnumber}          = $order->number;
+  $::form->{department_id}      = $order->department_id;
+  $::form->{currency}           = $order->currency->name;
+  $::form->{taxincluded}        = 1; # we use amount below, so tax is included
+  $::form->{transdate}          = $today->to_kivitendo;
+  $::form->{duedate}            = $today->to_kivitendo;
+  $::form->{duedate}            = $order->payment_terms->calc_date(reference_date => $today)->to_kivitendo if $order->payment_terms;
+  $::form->{deliverydate}       = $order->reqdate->to_kivitendo                                            if $order->reqdate;
+  create_links();
+
+  my $config_po_ap_workflow_chart_id = $::instance_conf->get_workflow_po_ap_chart_id;
+
+  my ($first_taxchart, $default_taxchart, $taxchart_to_use);
+  my @taxcharts = ();
+  @taxcharts    = GL->get_active_taxes_for_chart($config_po_ap_workflow_chart_id, $::form->{transdate}) if (defined $config_po_ap_workflow_chart_id);
+  foreach my $item (@taxcharts) {
+    $first_taxchart   //= $item;
+    $default_taxchart   = $item if $item->{is_default};
+  }
+  $taxchart_to_use      = $default_taxchart // $first_taxchart;
+
+  my %pat = $order->calculate_prices_and_taxes;
+  my $row = 1;
+  foreach my $amount_chart (keys %{$pat{amounts}}) {
+    my $tax = SL::DB::Manager::Tax->find_by(id => $pat{amounts}->{$amount_chart}->{tax_id});
+    # If tax chart from order for this amount is active, use it. Use default or first tax chart for selected chart else.
+    if (defined $config_po_ap_workflow_chart_id) {
+      $taxchart_to_use = (first {$_->{id} == $tax->id} @taxcharts) // $taxchart_to_use;
+    } else {
+      $taxchart_to_use = $tax;
+    }
+
+    $::form->{"AP_amount_chart_id_$row"}          = $config_po_ap_workflow_chart_id // $amount_chart;
+    $::form->{"previous_AP_amount_chart_id_$row"} = $::form->{"AP_amount_chart_id_$row"};
+    $::form->{"amount_$row"}                      = $::form->format_amount(\%::myconfig, $pat{amounts}->{$amount_chart}->{amount} * (1 + $tax->rate), 2);
+    $::form->{"taxchart_$row"}                    = $taxchart_to_use->id . '--' . $taxchart_to_use->rate;
+    $::form->{"project_id_$row"}                  = $order->globalproject_id;
+
+    $row++;
+  }
+
+  my $last_used_ap_chart               = SL::DB::Vendor->load_cached($::form->{vendor_id})->last_used_ap_chart;
+  $::form->{"AP_amount_chart_id_$row"} = $last_used_ap_chart->id if $last_used_ap_chart;
+  $::form->{rowcount}                  = $row;
+
+  update(
+    keep_rows_without_amount => 1,
+    dont_add_new_row         => 1,
+  );
+}
+
 sub setup_ap_search_action_bar {
   my %params = @_;