Angebote: neue Felder Auftragswahrscheinlichkeit, Voraus. Abrechnungsdatum
[kivitendo-erp.git] / bin / mozilla / oe.pl
index 883507a..2d82b9d 100644 (file)
@@ -35,6 +35,7 @@
 use Carp;
 use POSIX qw(strftime);
 
+use SL::DB::Order;
 use SL::DO;
 use SL::FU;
 use SL::OE;
@@ -89,6 +90,16 @@ sub check_oe_access {
   $main::auth->assert($right);
 }
 
+sub check_oe_conversion_to_sales_invoice_allowed {
+  return 1 if  $::form->{type} !~ m/^sales/;
+  return 1 if ($::form->{type} =~ m/quotation/) && $::instance_conf->get_allow_sales_invoice_from_sales_quotation;
+  return 1 if ($::form->{type} =~ m/order/)     && $::instance_conf->get_allow_sales_invoice_from_sales_order;
+
+  $::form->show_generic_error($::locale->text("You do not have the permissions to access this function."));
+
+  return 0;
+}
+
 sub set_headings {
   $main::lxdebug->enter_sub();
 
@@ -312,6 +323,18 @@ sub form_header {
   # Container for template variables. Unfortunately this has to be
   # visible in form_footer too, so package local level and not my here.
   %TMPL_VAR = ();
+  if ($form->{id}) {
+    my $obj = SL::DB::Order->new(id => $form->{id})->load;
+    $TMPL_VAR{warn_save_active_periodic_invoice} =
+         $obj->is_type('sales_order')
+      && $obj->periodic_invoices_config
+      && $obj->periodic_invoices_config->active
+      && (   !$obj->periodic_invoices_config->end_date
+          || ($obj->periodic_invoices_config->end_date > DateTime->today_local))
+      && $obj->periodic_invoices_config->get_previous_billed_period_start_date;
+
+    $TMPL_VAR{oe_obj} = $obj;
+  }
 
   $form->{defaultcurrency} = $form->get_default_currency(\%myconfig);
 
@@ -343,12 +366,12 @@ sub form_header {
 
   # label subs
   my $employee_list_query_gen      = sub { $::form->{$_[0]} ? [ or => [ id => $::form->{$_[0]}, deleted => 0 ] ] : [ deleted => 0 ] };
-  $TMPL_VAR{ALL_EMPLOYEES}         = SL::DB::Manager::Employee->get_all(query => $employee_list_query_gen->('employee_id'));
-  $TMPL_VAR{ALL_SALESMEN}          = SL::DB::Manager::Employee->get_all(query => $employee_list_query_gen->('salesman_id'));
-  $TMPL_VAR{ALL_SHIPTO}            = SL::DB::Manager::Shipto->get_all(query => [
+  $TMPL_VAR{ALL_EMPLOYEES}         = SL::DB::Manager::Employee->get_all_sorted(query => $employee_list_query_gen->('employee_id'));
+  $TMPL_VAR{ALL_SALESMEN}          = SL::DB::Manager::Employee->get_all_sorted(query => $employee_list_query_gen->('salesman_id'));
+  $TMPL_VAR{ALL_SHIPTO}            = SL::DB::Manager::Shipto->get_all_sorted(query => [
     or => [ trans_id  => $::form->{"$::form->{vc}_id"} * 1, and => [ shipto_id => $::form->{shipto_id} * 1, trans_id => undef ] ]
   ]);
-  $TMPL_VAR{ALL_CONTACTS}          = SL::DB::Manager::Contact->get_all(query => [
+  $TMPL_VAR{ALL_CONTACTS}          = SL::DB::Manager::Contact->get_all_sorted(query => [
     or => [
       cp_cv_id => $::form->{"$::form->{vc}_id"} * 1,
       and      => [
@@ -415,7 +438,7 @@ sub form_header {
     $::request->{layout}->add_javascripts_inline("alert('$credittext');");
   }
 
-  $::request->{layout}->add_javascripts_inline("\$(function(){$dispatch_to_popup})");
+  $::request->{layout}->add_javascripts_inline("\$(function(){$dispatch_to_popup});");
   $TMPL_VAR{dateformat}          = $myconfig{dateformat};
   $TMPL_VAR{numberformat}        = $myconfig{numberformat};
 
@@ -429,19 +452,20 @@ sub form_header {
     }
   }
 
-  $form->{javascript} .= qq|<script type="text/javascript" src="js/show_form_details.js"></script>|;
-  $form->{javascript} .= qq|<script type="text/javascript" src="js/show_history.js"></script>|;
-  $form->{javascript} .= qq|<script type="text/javascript" src="js/show_vc_details.js"></script>|;
+  $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.SalesPurchase show_form_details show_history show_vc_details ckeditor/ckeditor ckeditor/adapters/jquery));
 
   $form->header;
-
+  if ($form->{CFDD_shipto} && $form->{CFDD_shipto_id} ) {
+      $form->{shipto_id} = $form->{CFDD_shipto_id};
+  }
   $TMPL_VAR{HIDDENS} = [ map { name => $_, value => $form->{$_} },
      qw(id action type vc formname media format proforma queued printed emailed
         title creditlimit creditremaining tradediscount business
         max_dunning_level dunning_amount shiptoname shiptostreet shiptozipcode
-        shiptocity shiptocountry shiptocontact shiptophone shiptofax
+        CFDD_shipto CFDD_shipto_id shiptocity shiptocountry shiptocontact shiptophone shiptofax
         shiptodepartment_1 shiptodepartment_2 shiptoemail shiptocp_gender
-        message email subject cc bcc taxpart taxservice taxaccounts cursor_fokus),
+        message email subject cc bcc taxpart taxservice taxaccounts cursor_fokus
+        show_details),
         @custom_hiddens,
         map { $_.'_rate', $_.'_description', $_.'_taxnumber' } split / /, $form->{taxaccounts} ];  # deleted: discount
 
@@ -455,6 +479,8 @@ sub form_header {
      is_pur_ord      => scalar ($form->{type} =~ /purchase_order$/),
   );
 
+  $TMPL_VAR{ORDER_PROBABILITIES} = [ map { { title => ($_ * 10) . '%', id => $_ * 10 } } (0..10) ];
+
   print $form->parse_html_template("oe/form_header", { %TMPL_VAR });
 
   $main::lxdebug->leave_sub();
@@ -727,11 +753,13 @@ sub search {
                    "$form->{vc}s" => "ALL_VC",
                    "taxzones"     => "ALL_TAXZONES",
                    "business_types" => "ALL_BUSINESS_TYPES",);
-  $form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all(query => [ deleted => 0 ]);
+  $form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all_sorted(query => [ deleted => 0 ]);
 
   # constants and subs for template
   $form->{vc_keys}         = sub { "$_[0]->{name}--$_[0]->{id}" };
 
+  $form->{ORDER_PROBABILITIES} = [ map { { title => ($_ * 10) . '%', id => $_ * 10 } } (0..10) ];
+
   $form->header();
 
   print $form->parse_html_template('oe/search', {
@@ -786,9 +814,10 @@ sub orders {
   my @columns = (
     "transdate",               "reqdate",
     "id",                      $ordnumber,
-    "customernumber",
+    "cusordnumber",            "customernumber",
     "name",                    "netamount",
     "tax",                     "amount",
+    "remaining_netamount",     "remaining_amount",
     "curr",                    "employee",
     "salesman",
     "shipvia",                 "globalprojectnumber",
@@ -798,6 +827,7 @@ sub orders {
     "vcnumber",                "ustid",
     "country",                 "shippingpoint",
     "taxzone",
+    "order_probability",       "expected_billing_date", "expected_netamount",
   );
 
   # only show checkboxes if gotten here via sales_order form.
@@ -810,6 +840,8 @@ sub orders {
   $form->{l_delivered}         = "Y"                     if ($form->{delivered} && $form->{notdelivered});
   $form->{l_periodic_invoices} = "Y"                     if ($form->{periodic_invoices_active} && $form->{periodic_invoices_inactive});
 
+  map { $form->{"l_${_}"} = 'Y' } qw(order_probability expected_billing_date expected_netamount) if $form->{l_order_probability_expected_billing_date};
+
   my $attachment_basename;
   if ($form->{vc} eq 'vendor') {
     if ($form->{type} eq 'purchase_order') {
@@ -833,10 +865,11 @@ sub orders {
   my $report = SL::ReportGenerator->new(\%myconfig, $form);
 
   my @hidden_variables = map { "l_${_}" } @columns;
-  push @hidden_variables, "l_subtotal", $form->{vc}, qw(l_closed l_notdelivered open closed delivered notdelivered ordnumber quonumber
+  push @hidden_variables, "l_subtotal", $form->{vc}, qw(l_closed l_notdelivered open closed delivered notdelivered ordnumber quonumber cusordnumber
                                                         transaction_description transdatefrom transdateto type vc employee_id salesman_id
                                                         reqdatefrom reqdateto projectnumber project_id periodic_invoices_active periodic_invoices_inactive
-                                                        business_id shippingpoint taxzone_id);
+                                                        business_id shippingpoint taxzone_id
+                                                        order_probability_op order_probability_value expected_billing_date_from expected_billing_date_to);
 
   my   @keys_for_url = grep { $form->{$_} } @hidden_variables;
   push @keys_for_url, 'taxzone_id' if $form->{taxzone_id} ne ''; # taxzone_id could be 0
@@ -850,11 +883,14 @@ sub orders {
     'id'                      => { 'text' => $locale->text('ID'), },
     'ordnumber'               => { 'text' => $locale->text('Order'), },
     'quonumber'               => { 'text' => $form->{type} eq "request_quotation" ? $locale->text('RFQ') : $locale->text('Quotation'), },
+    'cusordnumber'            => { 'text' => $locale->text('Customer Order Number'), },
     'name'                    => { 'text' => $form->{vc} eq 'customer' ? $locale->text('Customer') : $locale->text('Vendor'), },
     'customernumber'          => { 'text' => $locale->text('Customer Number'), },
     'netamount'               => { 'text' => $locale->text('Amount'), },
     'tax'                     => { 'text' => $locale->text('Tax'), },
     'amount'                  => { 'text' => $locale->text('Total'), },
+    'remaining_amount'        => { 'text' => $locale->text('Remaining Amount'), },
+    'remaining_netamount'     => { 'text' => $locale->text('Remaining Net Amount'), },
     'curr'                    => { 'text' => $locale->text('Curr'), },
     'employee'                => { 'text' => $locale->text('Employee'), },
     'salesman'                => { 'text' => $locale->text('Salesman'), },
@@ -871,14 +907,17 @@ sub orders {
     'periodic_invoices'       => { 'text' => $locale->text('Per. Inv.'), },
     'shippingpoint'           => { 'text' => $locale->text('Shipping Point'), },
     'taxzone'                 => { 'text' => $locale->text('Steuersatz'), },
+    'order_probability'       => { 'text' => $locale->text('Order probability'), },
+    'expected_billing_date'   => { 'text' => $locale->text('Exp. bill. date'), },
+    'expected_netamount'      => { 'text' => $locale->text('Exp. netamount'), },
   );
 
-  foreach my $name (qw(id transdate reqdate quonumber ordnumber name employee salesman shipvia transaction_description shippingpoint taxzone)) {
+  foreach my $name (qw(id transdate reqdate quonumber ordnumber cusordnumber name employee salesman shipvia transaction_description shippingpoint taxzone)) {
     my $sortdir                 = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir};
     $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir";
   }
 
-  my %column_alignment = map { $_ => 'right' } qw(netamount tax amount curr);
+  my %column_alignment = map { $_ => 'right' } qw(netamount tax amount curr remaining_amount remaining_netamount order_probability expected_billing_date expected_netamount);
 
   $form->{"l_type"} = "Y";
   map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns;
@@ -896,6 +935,7 @@ sub orders {
   push @options, $locale->text('Vendor')                  . " : $form->{vendor}"                          if $form->{vendor};
   push @options, $locale->text('Department')              . " : $department"                              if $form->{department};
   push @options, $locale->text('Order Number')            . " : $form->{ordnumber}"                       if $form->{ordnumber};
+  push @options, $locale->text('Customer Order Number')   . " : $form->{cusordnumber}"                    if $form->{cusordnumber};
   push @options, $locale->text('Notes')                   . " : $form->{notes}"                           if $form->{notes};
   push @options, $locale->text('Transaction description') . " : $form->{transaction_description}"         if $form->{transaction_description};
   push @options, $locale->text('Shipping Point')          . " : $form->{shippingpoint}"                   if $form->{shippingpoint};
@@ -923,6 +963,16 @@ sub orders {
     push @options, $locale->text('Steuersatz') . " : " . SL::DB::TaxZone->new(id => $form->{taxzone_id})->load->description;
   }
 
+  if (($form->{order_probability_value} || '') ne '') {
+    push @options, $::locale->text('Order probability') . ' ' . ($form->{order_probability_op} eq 'le' ? '<=' : '>=') . ' ' . $form->{order_probability_value} . '%';
+  }
+
+  if ($form->{expected_billing_date_from} or $form->{expected_billing_date_to}) {
+    push @options, $locale->text('Expected billing date');
+    push @options, $locale->text('From') . " " . $locale->date(\%myconfig, $form->{expected_billing_date_from}, 1) if $form->{expected_billing_date_from};
+    push @options, $locale->text('Bis')  . " " . $locale->date(\%myconfig, $form->{expected_billing_date_to},   1) if $form->{expected_billing_date_to};
+  }
+
   $report->set_options('top_info_text'        => join("\n", @options),
                        'raw_top_info_text'    => $form->parse_html_template('oe/orders_top'),
                        'raw_bottom_info_text' => $form->parse_html_template('oe/orders_bottom', { 'SHOW_CONTINUE_BUTTON' => $allow_multiple_orders }),
@@ -939,7 +989,8 @@ sub orders {
   # escape callback for href
   my $callback = $form->escape($href);
 
-  my @subtotal_columns = qw(netamount amount marge_total marge_percent);
+  my @subtotal_columns = qw(netamount amount marge_total marge_percent remaining_amount remaining_netamount);
+  push @subtotal_columns, 'expected_netamount' if $form->{l_order_probability_expected_billing_date};
 
   my %totals    = map { $_ => 0 } @subtotal_columns;
   my %subtotals = map { $_ => 0 } @subtotal_columns;
@@ -962,7 +1013,9 @@ sub orders {
     $subtotals{marge_percent} = $subtotals{netamount} ? ($subtotals{marge_total} * 100 / $subtotals{netamount}) : 0;
     $totals{marge_percent}    = $totals{netamount}    ? ($totals{marge_total}    * 100 / $totals{netamount}   ) : 0;
 
-    map { $oe->{$_} = $form->format_amount(\%myconfig, $oe->{$_}, 2) } qw(netamount tax amount marge_total marge_percent);
+    map { $oe->{$_} = $form->format_amount(\%myconfig, $oe->{$_}, 2) } qw(netamount tax amount marge_total marge_percent remaining_amount remaining_netamount expected_netamount);
+
+    $oe->{order_probability} = ($oe->{order_probability} || 0) . '%';
 
     my $row = { };
 
@@ -1119,10 +1172,8 @@ sub save_and_close {
 
   }
 
-  # get new number in sequence if no number is given or if saveasnew was requested
-  if (!$form->{$ordnumber} || $form->{saveasnew}) {
-    $form->{$ordnumber} = $form->update_defaults(\%myconfig, $numberfld);
-  }
+  # get new number in sequence if saveasnew was requested
+  delete $form->{$ordnumber} if $form->{saveasnew};
 
   relink_accounts();
 
@@ -1229,10 +1280,6 @@ sub save {
 
   }
 
-  # value of $ordnumber is ordnumber or quonumber
-  $form->{$ordnumber} = $form->update_defaults(\%myconfig, $numberfld)
-    unless $form->{$ordnumber};
-
   relink_accounts();
 
   OE->save(\%myconfig, \%$form);
@@ -1300,6 +1347,7 @@ sub invoice {
   my $locale   = $main::locale;
 
   check_oe_access();
+  check_oe_conversion_to_sales_invoice_allowed();
   $main::auth->assert($form->{type} eq 'purchase_order' || $form->{type} eq 'request_quotation' ? 'vendor_invoice_edit' : 'invoice_edit');
 
   $form->{old_salesman_id} = $form->{salesman_id};
@@ -1358,8 +1406,7 @@ sub invoice {
     $exchangerate = $form->check_exchangerate(\%myconfig, $form->{currency}, $orddate, $buysell);
 
     if (!$exchangerate) {
-      &backorder_exchangerate($orddate, $buysell);
-      ::end_of_request();
+      $exchangerate = 0;
     }
   }
 
@@ -1450,75 +1497,6 @@ sub invoice {
   $main::lxdebug->leave_sub();
 }
 
-sub backorder_exchangerate {
-  $main::lxdebug->enter_sub();
-
-  my $form     = $main::form;
-  my $locale   = $main::locale;
-
-  check_oe_access();
-
-  my ($orddate, $buysell) = @_;
-
-  $form->header;
-
-  print qq|
-<form method=post action=$form->{script}>
-|;
-
-  # delete action variable
-  map { delete $form->{$_} } qw(action header exchangerate);
-
-  foreach my $key (keys %$form) {
-    next if (($key eq 'login') || ($key eq 'password') || ('' ne ref $form->{$key}));
-    $form->{$key} =~ s/\"/&quot;/g;
-    print qq|<input type=hidden name=$key value="$form->{$key}">\n|;
-  }
-
-  $form->{title} = $locale->text('Add Exchangerate');
-
-  print qq|
-
-<input type=hidden name=exchangeratedate value=$orddate>
-<input type=hidden name=buysell value=$buysell>
-
-<table width=100%>
-  <tr><th class=listtop>$form->{title}</th></tr>
-  <tr height="5"></tr>
-  <tr>
-    <td>
-      <table>
-        <tr>
-          <th align=right>| . $locale->text('Currency') . qq|</th>
-          <td>$form->{currency}</td>
-        </tr>
-        <tr>
-          <th align=right>| . $locale->text('Date') . qq|</th>
-          <td>$orddate</td>
-        </tr>
-        <tr>
-          <th align=right>| . $locale->text('Exchangerate') . qq|</th>
-          <td><input name=exchangerate size=11></td>
-        </tr>
-      </table>
-    </td>
-  </tr>
-</table>
-
-<hr size=3 noshade>
-
-<br>
-<input type=hidden name=nextsub value=save_exchangerate>
-
-<input name=action class=submit type=submit value="|
-    . $locale->text('Continue') . qq|">
-
-</form>
-|;
-
-  $main::lxdebug->leave_sub();
-}
-
 sub save_exchangerate {
   $main::lxdebug->enter_sub();
 
@@ -1669,6 +1647,7 @@ sub check_for_direct_delivery_yes {
   delete @{$form}{grep /^shipto/, keys %{ $form }};
   map { s/^CFDD_//; $form->{$_} = $form->{"CFDD_${_}"} } grep /^CFDD_/, keys %{ $form };
   $form->{shipto} = 1;
+  $form->{CFDD_shipto} = 1;
   purchase_order();
   $main::lxdebug->leave_sub();
 }
@@ -1682,6 +1661,7 @@ sub check_for_direct_delivery_no {
 
   $form->{direct_delivery_checked} = 1;
   delete @{$form}{grep /^shipto/, keys %{ $form }};
+  $form->{CFDD_shipto} = 0;
   purchase_order();
 
   $main::lxdebug->leave_sub();
@@ -1998,13 +1978,13 @@ sub edit_periodic_invoices_config {
 
   if ('HASH' ne ref $config) {
     $config =  { periodicity             => 'y',
-                 start_date_as_date      => $::form->{transdate},
+                 start_date_as_date      => $::form->{transdate} || $::form->current_date,
                  extend_automatically_by => 12,
                  active                  => 1,
                };
   }
 
-  $config->{periodicity} = 'm' if none { $_ eq $config->{periodicity} } qw(m q y);
+  $config->{periodicity} = 'm' if none { $_ eq $config->{periodicity} } qw(m q y);
 
   $::form->get_lists(printers => "ALL_PRINTERS",
                      charts   => { key       => 'ALL_CHARTS',
@@ -2030,9 +2010,10 @@ sub save_periodic_invoices_config {
 
   my $config = { active                  => $::form->{active}     ? 1 : 0,
                  terminated              => $::form->{terminated} ? 1 : 0,
-                 periodicity             => (any { $_ eq $::form->{periodicity} } qw(m q y)) ? $::form->{periodicity} : 'm',
+                 periodicity             => (any { $_ eq $::form->{periodicity} } qw(m q y)) ? $::form->{periodicity} : 'm',
                  start_date_as_date      => $::form->{start_date_as_date},
                  end_date_as_date        => $::form->{end_date_as_date},
+                 first_billing_date_as_date => $::form->{first_billing_date_as_date},
                  print                   => $::form->{print} ? 1 : 0,
                  printer_id              => $::form->{print} ? $::form->{printer_id} * 1 : undef,
                  copies                  => $::form->{copies} * 1 ? $::form->{copies} : 1,
@@ -2066,9 +2047,12 @@ sub _oe_remove_delivered_or_billed_rows {
   my %handled_base_qtys;
   foreach my $record (@{ $ord_quot->linked_records(%args) }) {
     next if $ord_quot->is_sales != $record->is_sales;
+    next if $record->type eq 'invoice' && $record->storno;
 
     foreach my $item (@{ $record->items }) {
-      $handled_base_qtys{ $item->parts_id } += $item->qty * $item->unit_obj->base_factor;
+      my $key  = $item->parts_id;
+      $key    .= ':' . $item->serialnumber if $item->serialnumber;
+      $handled_base_qtys{$key} += $item->qty * $item->unit_obj->base_factor;
     }
   }