From: Joachim Zach Date: Mon, 26 Apr 2010 07:26:44 +0000 (+0200) Subject: Optionale minimale Excel-Unterstützung für Druckvorlagen (Austausch von Platzhalter... X-Git-Tag: release-2.6.2beta1~342^2~9 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=90815a31b45ced8f49c31502cff1c8155e692a7a;p=kivitendo-erp.git Optionale minimale Excel-Unterstützung für Druckvorlagen (Austausch von Platzhalter-Variablen in Excel-Dateien). Entsprechend noch für strict angepasst --- diff --git a/SL/CT.pm b/SL/CT.pm index a661e8c58..9089aabcc 100644 --- a/SL/CT.pm +++ b/SL/CT.pm @@ -1089,4 +1089,80 @@ sub get_bank_info { return $result; } +sub parse_excel_file { + $main::lxdebug->enter_sub(); + + my ($self, $myconfig, $form) = @_; + my $locale = $main::locale; + + $form->{formname} = 'sales_quotation'; + $form->{type} = 'sales_quotation'; + $form->{format} = 'excel'; + $form->{media} = 'screen'; + $form->{quonumber} = 1; + + + # $form->{"notes"} will be overridden by the customer's/vendor's "notes" field. So save it here. + $form->{ $form->{"formname"} . "notes" } = $form->{"notes"}; + + my $inv = "quo"; + my $due = "req"; + $form->{"${inv}date"} = $form->{transdate}; + $form->{label} = $locale->text('Quotation'); + my $numberfld = "sqnumber"; + my $order = 1; + + # assign number + $form->{what_done} = $form->{formname}; + + map({ delete($form->{$_}); } grep(/^cp_/, keys(%{ $form }))); + + my $output_dateformat = $myconfig->{"dateformat"}; + my $output_numberformat = $myconfig->{"numberformat"}; + my $output_longdates = 1; + + # map login user variables + map { $form->{"login_$_"} = $myconfig->{$_} } ("name", "email", "fax", "tel", "company"); + + # format item dates + for my $field (qw(transdate_oe deliverydate_oe)) { + map { + $form->{$field}[$_] = $locale->date($myconfig, $form->{$field}[$_], 1); + } 0 .. $#{ $form->{$field} }; + } + + if ($form->{shipto_id}) { + $form->get_shipto($myconfig); + } + + $form->{notes} =~ s/^\s+//g; + + $form->{templates} = $myconfig->{templates}; + + delete $form->{printer_command}; + + $form->get_employee_info($myconfig); + + my ($cvar_date_fields, $cvar_number_fields) = CVar->get_field_format_list('module' => 'CT', 'prefix' => 'vc_'); + + if (scalar @{ $cvar_date_fields }) { + format_dates($output_dateformat, $output_longdates, @{ $cvar_date_fields }); + } + + while (my ($precision, $field_list) = each %{ $cvar_number_fields }) { + reformat_numbers($output_numberformat, $precision, @{ $field_list }); + } + + $form->{excel} = 1; + my $extension = 'xls'; + + my $form->{IN} = "$form->{formname}.${extension}"; + + delete $form->{OUT}; + + $form->parse_template($myconfig, $main::userspath); + + $main::lxdebug->leave_sub(); +} + 1; diff --git a/SL/Form.pm b/SL/Form.pm index 2ba19b65c..11f88ad5a 100644 --- a/SL/Form.pm +++ b/SL/Form.pm @@ -1178,6 +1178,10 @@ sub parse_template { } elsif ( $self->{"format"} =~ /elstertaxbird/i ) { $template = XMLTemplate->new($self->{"IN"}, $self, $myconfig, $userspath); + } elsif ( $self->{"format"} =~ /excel/i ) { + $template = ExcelTemplate->new($self->{"IN"}, $self, $myconfig, $userspath); + $ext_for_format = 'xls'; + } elsif ( defined $self->{'format'}) { $self->error("Outputformat not defined. This may be a future feature: $self->{'format'}"); @@ -1385,6 +1389,7 @@ sub get_extension_for_format { my $extension = $self->{format} =~ /pdf/i ? ".pdf" : $self->{format} =~ /postscript/i ? ".ps" : $self->{format} =~ /opendocument/i ? ".odt" + : $self->{format} =~ /excel/i ? ".xls" : $self->{format} =~ /html/i ? ".html" : ""; diff --git a/SL/Template.pm b/SL/Template.pm index 3556dc49a..7f4d27571 100644 --- a/SL/Template.pm +++ b/SL/Template.pm @@ -1477,4 +1477,95 @@ sub uses_temp_file { return 1; } + +########################################################## +#### +#### ExcelTemplate +#### +########################################################## + +package ExcelTemplate; + +use vars qw(@ISA); + +@ISA = qw(SimpleTemplate); + +sub new { + my $type = shift; + + my $self = $type->SUPER::new(@_); + + return $self; +} +sub _init { + my $self = shift; + + $self->{source} = shift; + $self->{form} = shift; + $self->{myconfig} = shift; + $self->{userspath} = shift; + + $self->{error} = undef; + + $self->set_tag_style('<<', '>>'); +} + +sub get_mime_type() { + my ($self) = @_; + + return "application/msexcel"; +} + +sub uses_temp_file { + return 1; +} + +sub parse { + $main::lxdebug->enter_sub(); + + my $self = shift; + local *OUT = shift; + my $form = $self->{"form"}; + + open(IN, "$form->{templates}/$form->{IN}") or do { $self->{"error"} = "$!"; return 0; }; + my @lines = ; + close IN; + + my $contents = join("", @lines); + my @indices; + $contents =~ s{ + $self->{tag_start} [<]* (\s?) [<>\s]* ([\w\s]+) [<>\s]* $self->{tag_end} + }{ + $self->format_vars(align_right => $1 ne '', varstring => $2, length => length($&), indices => \@indices) + }egx; + + if (!defined($contents)) { + $main::lxdebug->leave_sub(); + return 0; + } + + print OUT $contents; + + $main::lxdebug->leave_sub(); + return 1; +} + +sub format_vars { + my ($self, %params) = @_; + my $form = $self->{"form"}; + my @indices = @{ $params{indices} }; + my $align_right = $params{align_right}; + my $varstring = $params{varstring}; + my $length = $params{length}; + + $varstring =~ s/(\w+)/ $self->_get_loop_variable($1, 0, @indices) /eg; + my $old_string=$varstring; + my $new_string = sprintf "%*s", ($align_right ? 1 : -1 ) * $length, $varstring; + if (!defined($new_string) || $new_string eq ''){ + $main::lxdebug->message(0, 'varstring' . $varstring . "old" . $old_string); + # return substr $varstring, ($align_right ? (0, $length) : -$length); + } + return substr $new_string, ($align_right ? (0, $length) : -$length); +} + 1; diff --git a/bin/mozilla/io.pl b/bin/mozilla/io.pl index ce7ce7848..44ddc1675 100644 --- a/bin/mozilla/io.pl +++ b/bin/mozilla/io.pl @@ -1184,7 +1184,9 @@ sub print_options { (!$options{no_html}) ? opthash("html", $form->{DF}{html}, "HTML") : undef, ($main::opendocument_templates && !$options{no_opendocument}) ? - opthash("opendocument", $form->{DF}{opendocument}, $locale->text("OpenDocument/OASIS")) : undef; + opthash("opendocument", $form->{DF}{opendocument}, $locale->text("OpenDocument/OASIS")) : undef, + ($main::excel_templates && !$options{no_excel}) ? + opthash("excel", $form->{DF}{excel}, $locale->text("Excel")) : undef; push @LANGUAGE_ID, map { opthash($_->{id}, ($_->{id} eq $form->{language_id} ? 'selected' : ''), $_->{description}) } +{}, @{ $form->{languages} } @@ -1592,6 +1594,9 @@ sub print_form { } elsif ($form->{"format"} =~ /opendocument/) { $form->{opendocument} = 1; $extension = 'odt'; + } elsif ($form->{"format"} =~ /excel/) { + $form->{excel} = 1; + $extension = 'xls'; } my $email_extension = '_email' if (($form->{media} eq 'email') && (-f "$myconfig{templates}/$form->{formname}_email$form->{language}${printer_code}.${extension}")); diff --git a/config/lx-erp.conf b/config/lx-erp.conf index 91bfc83b4..300d1a7bc 100644 --- a/config/lx-erp.conf +++ b/config/lx-erp.conf @@ -42,6 +42,7 @@ $ENV{PERL5LIB} .= ":/sw/lib/perl5"; $webdav = 0; $lizenzen = 1; $vertreter = 0; +$excel_templates = 0; # Minimalunterstützung für Excel-Druckvorlagen # Zeige Felder für Mindesthaltbarkeitsdatum $show_best_before = 0; diff --git a/doc/changelog b/doc/changelog index 8b25926ec..67a492ccf 100644 --- a/doc/changelog +++ b/doc/changelog @@ -2,6 +2,21 @@ # Veränderungen von Lx-Office ERP # ################################### + + + + + + + + + + Kleinere neue Features und Detailverbesserungen: + + - Druckvorlage optional auf Excel erweitert, um Variablen die sich nicht in foreach-Schleifen + befinden anzuzeigen (s.a.: doc/excel_templates.txt). + + 2010-03-24 - Release 2.6.1 Größere neue Features: diff --git a/doc/excel_templates.txt b/doc/excel_templates.txt new file mode 100644 index 000000000..f08186202 --- /dev/null +++ b/doc/excel_templates.txt @@ -0,0 +1,79 @@ +Table of Contents +----------------- + +Inhalt der Anleitung +1 Zusammenfassung +2 Bedienung +3 Exceltemplate Syntax +4 Einschränkungen + + + +Zusammenfassung +--------------- + +Dieses Dokument beschreibt den Mechanismus, mit dem Exceltemplates abgearbeitet +werden, und die Einschränkungen die damit einhergehen. + + + +Bedienung +--------- + +Der Excel Mechanismus muss in der Konfigurationsdatei aktiviert werden. Die +Konfigurationsoption heißt: + + $excel_templates = 1; + +Eine Excelvorlage kann dann unter dem Namen einer beliebigen anderen Vorlage mit +der Endung .xls gespeichert werden. In den normalen Verkaufsmasken taucht nun +"Excel" als auswählbares Format auf, und kann von da an bnutzt weren wie Latex +oder OpenOffice Vorlagen. + +Der Sonderfall der Angebote aus der Kundenmaske ist ebenfalls eine +Angebotsvorlage, und wird unter dem internen Namen der Angebote +"sales_quotation.xls" gespeichert. + + + +Exceltemplate Syntax +-------------------- + +Einfache Syntax: <> + +Wobei "<<" und ">>" die Delimiter sind. Da Excel auf festen Breiten besteht, +kann der Tag künstlich verlängert werden, indem weitere "<" oder ">" gegefügt +werden. Der Tag muss nicht symmetrisch sein. + +Beispiel: <<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +Um die Limitierung der festen Breite zu reduzieren, können weitere Variablen in +einem Block interpoliert werden. Whitespace wird dazwishen dann erhalten. + +Beispiel: <<<<>>>>>>>>>>>>>>>>>>>>>>>>> + +Die Variablen werden interpoliert, und linksbündig mit Leerzeichen auf die +gewünschte Länge aufgefüllt. Ist der String zu lang, werden überzählige Zeichen +abgeschnitten. + +Es ist ausserdem möglich Daten rechtsbündig darzustellen, wenn der Block mit +einem Leerzeichen anfängt. + +Beispiel: <<<<<< varname>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + +würde rechtsbündig triggern. Wenn bei rechtsbündiger Ausrichtung Text +abgeschnitten werden muss, wird er vom linken Ende entfernt. + + + +Einschränkungen +--------------- + +Das Excelformat bis 2002 ist ein binäres Format, und kann nicht mit vertretbarem +Aufwand editiert werden. Der Templatemechanismus beschränkt sich daher darauf, +Textstellen _exakt_ durch einen anderen Text zu ersetzen. + +Aus dem gleichen Grund sind die Templatekonstrukte <% if %> und <% foreach %> +nicht vorhanden. Der Delimiter <% %> kommt in den Headerinformationen evtl vor, +deshalb wurde auf den sichereren "<<"/">>" gewechselt. +