SameSite-Attribut des Session-Cookies auf Strict setzen
[kivitendo-erp.git] / SL / Form.pm
index e6cb332..fd79b96 100644 (file)
@@ -61,6 +61,7 @@ use SL::DBConnect;
 use SL::DBUtils;
 use SL::DB::AdditionalBillingAddress;
 use SL::DB::Customer;
+use SL::DB::CustomVariableConfig;
 use SL::DB::Default;
 use SL::DB::PaymentTerm;
 use SL::DB::Vendor;
@@ -388,6 +389,7 @@ sub create_http_response {
                                      '-path'    => $uri->path,
                                      '-expires' => '+' . $::auth->{session_timeout} . 'm',
                                      '-secure'  => $::request->is_https);
+      $session_cookie = "$session_cookie; SameSite=strict";
     }
   }
 
@@ -435,6 +437,8 @@ sub header {
     common part_selection
   ), "jquery/ui/i18n/jquery.ui.datepicker-$::myconfig{countrycode}");
 
+  $layout->use_javascript("$_.js") for @{ $params{use_javascripts} // [] };
+
   $self->{favicon} ||= "favicon.ico";
   $self->{titlebar} = join ' - ', grep $_, $self->{title}, $self->{login}, $::myconfig{dbname}, $self->read_version if $self->{title} || !$self->{titlebar};
 
@@ -856,6 +860,9 @@ sub parse_template {
   # therefore copy to webdav, even if we do not have the webdav feature enabled (just archive)
   my $copy_to_webdav =  $::instance_conf->get_webdav_documents && !$self->{preview} && $self->{tmpdir} && $self->{tmpfile} && $self->{type}
                         && $self->{type} ne 'statement';
+
+  $self->{attachment_filename} ||= $self->generate_attachment_filename;
+
   if ( $ext_for_format eq 'pdf' && $self->doc_storage_enabled ) {
     $self->append_general_pdf_attachments(filepath =>  $self->{tmpdir}."/".$self->{tmpfile},
                                           type     =>  $self->{type});
@@ -872,7 +879,6 @@ sub parse_template {
 
     if (!$self->{preview} && $self->{attachment_type} !~ m{^dunning} && $self->doc_storage_enabled)
     {
-      $self->{attachment_filename} ||= $self->generate_attachment_filename;
       $self->store_pdf($self);
     }
     $self->cleanup;
@@ -891,7 +897,6 @@ sub parse_template {
   }
 
   if ( !$self->{preview} && $ext_for_format eq 'pdf' && $self->{attachment_type} !~ m{^dunning} && $self->doc_storage_enabled) {
-    $self->{attachment_filename} ||= $self->generate_attachment_filename;
     my $file_obj = $self->store_pdf($self);
     $self->{print_file_id} = $file_obj->id if $file_obj;
   }
@@ -950,17 +955,15 @@ sub send_email {
   $mail->{to}     = $self->{EMAIL_RECIPIENT} ? $self->{EMAIL_RECIPIENT} : $self->{email};
   $mail->{from}   = qq|"$myconfig->{name}" <$myconfig->{email}>|;
   $mail->{fileid} = time() . '.' . $$ . '.';
+  $mail->{content_type}  =  "text/html";
   my $full_signature     =  $self->create_email_signature();
-  $full_signature        =~ s/\r//g;
 
   $mail->{attachments} =  [];
   my @attfiles;
   # if we send html or plain text inline
   if (($self->{format} eq 'html') && ($self->{sendmode} eq 'inline')) {
-    $mail->{content_type}   =  "text/html";
     $mail->{message}        =~ s/\r//g;
     $mail->{message}        =~ s{\n}{<br>\n}g;
-    $full_signature         =~ s{\n}{<br>\n}g;
     $mail->{message}       .=  $full_signature;
 
     open(IN, "<", $self->{tmpfile})
@@ -973,9 +976,10 @@ sub send_email {
     $attachment_name     =~ s{\.(.+?)$}{.${ext_for_format}} if ($ext_for_format);
 
     if (($self->{attachment_policy} // '') eq 'old_file') {
-      my ( $attfile ) = SL::File->get_all(object_id   => $self->{id},
-                                          object_type => $self->{formname},
-                                          file_type   => 'document');
+      my ( $attfile ) = SL::File->get_all(object_id     => $self->{id},
+                                          object_type   => $self->{type},
+                                          file_type     => 'document',
+                                          print_variant => $self->{formname},);
 
       if ($attfile) {
         $attfile->{override_file_name} = $attachment_name if $attachment_name;
@@ -1084,27 +1088,31 @@ sub get_formname_translation {
   local $::locale = Locale->new($self->{recipient_locale});
 
   my %formname_translations = (
-    bin_list                => $main::locale->text('Bin List'),
-    credit_note             => $main::locale->text('Credit Note'),
-    invoice                 => $main::locale->text('Invoice'),
-    invoice_copy            => $main::locale->text('Invoice Copy'),
-    pick_list               => $main::locale->text('Pick List'),
-    proforma                => $main::locale->text('Proforma Invoice'),
-    purchase_order          => $main::locale->text('Purchase Order'),
-    request_quotation       => $main::locale->text('RFQ'),
-    sales_order             => $main::locale->text('Confirmation'),
-    sales_quotation         => $main::locale->text('Quotation'),
-    storno_invoice          => $main::locale->text('Storno Invoice'),
-    sales_delivery_order    => $main::locale->text('Delivery Order'),
-    purchase_delivery_order => $main::locale->text('Delivery Order'),
-    dunning                 => $main::locale->text('Dunning'),
-    dunning1                => $main::locale->text('Payment Reminder'),
-    dunning2                => $main::locale->text('Dunning'),
-    dunning3                => $main::locale->text('Last Dunning'),
-    dunning_invoice         => $main::locale->text('Dunning Invoice'),
-    letter                  => $main::locale->text('Letter'),
-    ic_supply               => $main::locale->text('Intra-Community supply'),
-    statement               => $main::locale->text('Statement'),
+    bin_list                    => $main::locale->text('Bin List'),
+    credit_note                 => $main::locale->text('Credit Note'),
+    invoice                     => $main::locale->text('Invoice'),
+    invoice_copy                => $main::locale->text('Invoice Copy'),
+    invoice_for_advance_payment => $main::locale->text('Invoice for Advance Payment'),
+    final_invoice               => $main::locale->text('Final Invoice'),
+    pick_list                   => $main::locale->text('Pick List'),
+    proforma                    => $main::locale->text('Proforma Invoice'),
+    purchase_order              => $main::locale->text('Purchase Order'),
+    request_quotation           => $main::locale->text('RFQ'),
+    sales_order                 => $main::locale->text('Confirmation'),
+    sales_quotation             => $main::locale->text('Quotation'),
+    storno_invoice              => $main::locale->text('Storno Invoice'),
+    sales_delivery_order        => $main::locale->text('Delivery Order'),
+    purchase_delivery_order     => $main::locale->text('Delivery Order'),
+    supplier_delivery_order     => $main::locale->text('Supplier Delivery Order'),
+    rma_delivery_order          => $main::locale->text('RMA Delivery Order'),
+    dunning                     => $main::locale->text('Dunning'),
+    dunning1                    => $main::locale->text('Payment Reminder'),
+    dunning2                    => $main::locale->text('Dunning'),
+    dunning3                    => $main::locale->text('Last Dunning'),
+    dunning_invoice             => $main::locale->text('Dunning Invoice'),
+    letter                      => $main::locale->text('Letter'),
+    ic_supply                   => $main::locale->text('Intra-Community supply'),
+    statement                   => $main::locale->text('Statement'),
   );
 
   $main::lxdebug->leave_sub();
@@ -1130,11 +1138,11 @@ sub get_number_prefix_for_type {
   my ($self) = @_;
 
   my $prefix =
-      (first { $self->{type} eq $_ } qw(invoice credit_note)) ? 'inv'
-    : ($self->{type} =~ /_quotation$/)                        ? 'quo'
-    : ($self->{type} =~ /_delivery_order$/)                   ? 'do'
-    : ($self->{type} =~ /letter/)                             ? 'letter'
-    :                                                           'ord';
+      (first { $self->{type} eq $_ } qw(invoice invoice_for_advance_payment final_invoice credit_note)) ? 'inv'
+    : ($self->{type} =~ /_quotation$/)                                                                  ? 'quo'
+    : ($self->{type} =~ /_delivery_order$/)                                                             ? 'do'
+    : ($self->{type} =~ /letter/)                                                                       ? 'letter'
+    :                                                                                                     'ord';
 
   # better default like this?
   # : ($self->{type} =~ /(sales|purcharse)_order/           :  'ord';
@@ -1169,7 +1177,7 @@ sub generate_attachment_filename {
   my $attachment_filename = $main::locale->unquote_special_chars('HTML', $self->get_formname_translation());
   my $prefix              = $self->get_number_prefix_for_type();
 
-  if ($self->{preview} && (first { $self->{type} eq $_ } qw(invoice credit_note))) {
+  if ($self->{preview} && (first { $self->{type} eq $_ } qw(invoice invoice_for_advance_payment final_invoice credit_note))) {
     $attachment_filename .= ' (' . $recipient_locale->text('Preview') . ')' . $self->get_extension_for_format();
 
   } elsif ($attachment_filename && $self->{"${prefix}number"}) {
@@ -1231,10 +1239,12 @@ sub generate_email_body {
 
   return undef unless $body;
 
+  $body .= GenericTranslations->get(translation_type => "salutation_punctuation_mark", language_id => $self->{language_id});
+  $body  = '<p>' . $::locale->quote_special_chars('HTML', $body) . '</p>';
+
   my $translation_type = $params{translation_type} // "preset_text_$self->{formname}";
   my $main_body        = GenericTranslations->get(translation_type => $translation_type,                  language_id => $self->{language_id});
   $main_body           = GenericTranslations->get(translation_type => $params{fallback_translation_type}, language_id => $self->{language_id}) if !$main_body && $params{fallback_translation_type};
-  $body               .= GenericTranslations->get(translation_type => "salutation_punctuation_mark",      language_id => $self->{language_id}) . "\n\n";
   $body               .= $main_body;
 
   $body = $main::locale->unquote_special_chars('HTML', $body);
@@ -2516,7 +2526,7 @@ sub create_links {
            a.mtime, a.itime,
            a.intnotes, a.department_id, a.amount AS oldinvtotal,
            a.paid AS oldtotalpaid, a.employee_id, a.gldate, a.type,
-           a.globalproject_id, ${extra_columns}
+           a.globalproject_id, a.transaction_description, ${extra_columns}
            c.name AS $table,
            d.description AS department,
            e.name AS employee
@@ -2713,6 +2723,8 @@ sub lastname_used {
 }
 
 sub get_variable_content_types {
+  my ($self) = @_;
+
   my %html_variables = (
     longdescription  => 'html',
     partnotes        => 'html',
@@ -2725,7 +2737,34 @@ sub get_variable_content_types {
     header_text      => 'html',
     footer_text      => 'html',
   );
-  return \%html_variables;
+
+  return {
+    %html_variables,
+    $self->get_variable_content_types_for_cvars,
+  };
+}
+
+sub get_variable_content_types_for_cvars {
+  my ($self)       = @_;
+  my $html_configs = SL::DB::Manager::CustomVariableConfig->get_all(where => [ type => 'htmlfield' ]);
+  my %types;
+
+  if (@{ $html_configs }) {
+    my %prefix_by_module = (
+      Contacts => 'cp_cvar_',
+      CT       => 'vc_cvar_',
+      IC       => 'ic_cvar_',
+      Projects => 'project_cvar_',
+      ShipTo   => 'shiptocvar_',
+    );
+
+    foreach my $cfg (@{ $html_configs }) {
+      my $prefix = $prefix_by_module{$cfg->module};
+      $types{$prefix . $cfg->name} = 'html' if $prefix;
+    }
+  }
+
+  return %types;
 }
 
 sub current_date {
@@ -2912,6 +2951,8 @@ sub save_status {
 # $main::locale->text('UNDO TRANSFER')
 # $main::locale->text('UNIMPORT')
 # $main::locale->text('invoice')
+# $main::locale->text('invoice_for_advance_payment')
+# $main::locale->text('final_invoice')
 # $main::locale->text('proforma')
 # $main::locale->text('sales_order')
 # $main::locale->text('pick_list')
@@ -2956,7 +2997,7 @@ sub get_history {
       qq|SELECT h.employee_id, h.itime::timestamp(0) AS itime, h.addition, h.what_done, emp.name, h.snumbers, h.trans_id AS id | .
       qq|FROM history_erp h | .
       qq|LEFT JOIN employee emp ON (emp.id = h.employee_id) | .
-      qq|WHERE (trans_id = | . $trans_id . qq|) $restriction | .
+      qq|WHERE (trans_id = | . $dbh->quote($trans_id) . qq|) $restriction | .
       $order;
 
     my $sth = $dbh->prepare($query) || $self->dberror($query);
@@ -3408,19 +3449,11 @@ sub reformat_numbers {
 }
 
 sub create_email_signature {
-
   my $client_signature = $::instance_conf->get_signature;
   my $user_signature   = $::myconfig{signature};
 
-  my $signature = '';
-  if ( $client_signature or $user_signature ) {
-    $signature  = "\n\n-- \n";
-    $signature .= $user_signature   . "\n" if $user_signature;
-    $signature .= $client_signature . "\n" if $client_signature;
-  };
-  return $signature;
-
-};
+  return join '', grep { $_ } ($user_signature, $client_signature);
+}
 
 sub calculate_tax {
   # this function calculates the net amount and tax for the lines in ar, ap and