/doc/online/*/*.html
pod2html*
/doc/build/dobudish*
+/spool/*
my $dbh = $form->dbconnect($myconfig);
my $cv = $form->{db} eq "customer" ? "customer" : "vendor";
+ my $join_records = $form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber};
my $where = "1 = 1";
my @values;
$form->{sort} = $sortorder;
my $sortdir = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
- if ($sortorder !~ /(business|id)/ && 1 >= scalar grep { $form->{$_} } qw(l_ordnumber l_quonumber l_invnumber )) {
+ if ($sortorder !~ /(business|id)/ && !$join_records) {
$sortorder = "lower($sortorder) ${sortdir}";
} else {
$sortorder .= " ${sortdir}";
my $query =
qq|SELECT ct.*, b.description AS business | .
+ (qq|, NULL AS invnumber, NULL AS ordnumber, NULL AS quonumber, NULL AS invid, NULL AS module, NULL AS formtype, NULL AS closed | x!! $join_records) .
qq|FROM $cv ct | .
qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
qq|WHERE $where|;
my @saved_values = @values;
# redo for invoices, orders and quotations
- if ($form->{l_invnumber} || $form->{l_ordnumber} || $form->{l_quonumber}) {
- my ($ar, $union, $module);
- $query = "";
+ if ($join_records) {
+ my $union = "UNION";
if ($form->{l_invnumber}) {
my $ar = $cv eq 'customer' ? 'ar' : 'ap';
my $module = $ar eq 'ar' ? 'is' : 'ir';
-
- $query =
+ push(@values, @saved_values);
+ $query .=
+ qq| UNION | .
qq|SELECT ct.*, b.description AS business, | .
qq| a.invnumber, a.ordnumber, a.quonumber, a.id AS invid, | .
qq| '$module' AS module, 'invoice' AS formtype, | .
qq|JOIN $ar a ON (a.${cv}_id = ct.id) | .
qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
qq|WHERE $where AND (a.invoice = '1')|;
-
- $union = qq|UNION|;
}
if ( $form->{l_ordnumber} ) {
- if ($union eq "UNION") {
- push(@values, @saved_values);
- }
+ push(@values, @saved_values);
$query .=
- qq| $union | .
+ qq| UNION | .
qq|SELECT ct.*, b.description AS business,| .
qq| ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
qq| 'oe' AS module, 'order' AS formtype, o.closed | .
qq|JOIN oe o ON (o.${cv}_id = ct.id) | .
qq|LEFT JOIN business b ON (ct.business_id = b.id) | .
qq|WHERE $where AND (o.quotation = '0')|;
-
- $union = qq|UNION|;
}
if ( $form->{l_quonumber} ) {
- if ($union eq "UNION") {
- push(@values, @saved_values);
- }
+ push(@values, @saved_values);
$query .=
- qq| $union | .
+ qq| UNION | .
qq|SELECT ct.*, b.description AS business, | .
qq| ' ' AS invnumber, o.ordnumber, o.quonumber, o.id AS invid, | .
qq| 'oe' AS module, 'quotation' AS formtype, o.closed | .
profile => $profile,
ignore_unknown_columns => 1,
strict_profile => 1,
+ case_insensitive_header => 1,
map { ( $_ => $self->controller->profile->get($_) ) } qw(sep_char escape_char quote_char),
));
$profile{$col} = $name;
}
+ if ($self->can('all_cvar_configs')) {
+ for (@{ $self->all_cvar_configs }) {
+ $profile{ 'cvar_' . $_->name } = '';
+ }
+ }
+
$self->profile(\%profile);
}
$params{path_suffix} ||= '';
$params{schema} ||= '';
+ $params{path} = "sql/" . $params{dbdriver} . "-upgrade2" . $params{path_suffix};
map { $self->{$_} = $params{$_} } keys %params;
return $self;
}
+sub path {
+ $_[0]{path};
+}
+
sub parse_dbupdate_controls {
$::lxdebug->enter_sub();
local *IN;
my %all_controls;
- my $path = "sql/" . $self->{dbdriver} . "-upgrade2" . $self->{path_suffix};
+ my $path = $self->path;
foreach my $file_name (<$path/*.sql>, <$path/*.pl>) {
next unless (open(IN, $file_name));
use Rose::Object::MakeMethods::Generic scalar => [ qw(
file encoding sep_char quote_char escape_char header profile class
numberformat dateformat ignore_unknown_columns strict_profile _io _csv
- _objects _parsed _data _errors
+ _objects _parsed _data _errors all_cvar_configs case_insensitive_header
) ];
use SL::Helper::Csv::Dispatcher;
dateformat => 0,
ignore_unknown_columns => 0,
strict_profile => 0,
+ case_insensitive_header => 0,
});
my $self = bless {}, $class;
}
return unless $header;
- return $self->header([ map { lc } @$header ]);
+
+ # Special case: human stupidity
+ # people insist that case sensitivity doesn't exist and try to enter all
+ # sorts of stuff. at this point we've got a profile (with keys that represent
+ # valid methods), and a header full of strings. if two of them match, the user
+ # mopst likely meant that field, so rewrite the header
+ if ($self->case_insensitive_header) {
+ die 'case_insensitive_header is only possible with profile' unless $self->profile;
+ my @names = (
+ keys %{ $self->profile || {} },
+ );
+ for my $name (@names) {
+ for my $i (0..$#$header) {
+ $header->[$i] = $name if lc $header->[$i] eq lc $name;
+ }
+ }
+ }
+
+ return $self->header($header);
}
sub _parse_data {
will have to do that for yourself. Since you provided the profile, it is
assumed you know what to do in this case.
+If no profile is given, any header field found will be taken as is.
+
+If the path in a profile entry is empty, the field will be subjected to
+C<strict_profile> and C<case_insensitive_header> checking, will be parsed into
+C<get_data>, but will not be attempted to be dispatched into objects.
+
=item C<class>
If present, the line will be handed to the new sub of this class,
If set, the import will ignore unkown header columns. Useful for lazy imports,
but deactivated by default.
+=item C<case_insensitive_header>
+
+If set, header columns will be matched against profile entries case
+insensitive, and on match the profile name will be taken.
+
+Only works if a profile is given, will die otherwise.
+
+If both C<case_insensitive_header> and C<strict_profile> is set, matched header
+columns will be accepted.
+
=item C<strict_profile>
If set, all columns to be parsed must be specified in C<profile>. Every header
field not listed there will be treated like an unknown column.
+If both C<case_insensitive_header> and C<strict_profile> is set, matched header
+columns will be accepted.
+
=back
=head1 ERROR HANDLING
$self->unknown_column($col, undef);
}
} else {
- push @specs, $self->make_spec($col, $profile->{$col} || $col);
+ if (exists $profile->{$col}) {
+ push @specs, $self->make_spec($col, $profile->{$col});
+ } else {
+ push @specs, $self->make_spec($col, $col);
+ }
}
}
my ($self, $col, $path) = @_;
my $spec = { key => $col, steps => [] };
+
+ return unless $path;
+
my $cur_class = $self->_csv->class;
return unless $cur_class;
my $pricegroup_old = $form->{"pricegroup_old_$i"};
- # sellprice has format 13,0000 or 0,00000, can't check for 0 numerically
+ # sellprice has format 13,0000 or 0,00000, can't check for 0 numerically
my $sellprice = $form->{"sellprice_$i"};
my $pricegroup_id = $form->{"pricegroup_id_$i"};
$form->{"new_pricegroup_$i"} = $selectedpricegroup_id;
$pkr->{selected} = ' selected'; # unless $form->{selected};
# no customer pricesgroup set
- if ($pkr->{price_unfmt} == $pkr->{default_sellprice}) {
+ if ($pkr->{price_unfmt} == $pkr->{default_sellprice} || $form->{'sellprice_'.$i} * 1 > 1) {
$pkr->{price} = $form->{"sellprice_$i"};
} else {
-# this sub should not set anything and only return. --sschoeling, 20090506
-# is this correct? put in again... -- grichardson 20110119
$form->{"sellprice_$i"} = $pkr->{price};
}
}
sub menuitem_new {
- $main::lxdebug->enter_sub();
+ $main::lxdebug->enter_sub(LXDebug::DEBUG2());
my ($self, $name, $item) = @_;
$item->{href} .= "&" . $form->escape($key) . "=" . $form->escape($value);
}
- $main::lxdebug->leave_sub();
+ $main::lxdebug->leave_sub(LXDebug::DEBUG2());
}
sub access_control {
$zip->contents("content.xml", Encode::encode('utf-8-strict', $new_contents));
- my $styles = $zip->contents("styles.xml");
+ my $styles = Encode::decode('utf-8-strict', $zip->contents("styles.xml"));
if ($contents) {
my $new_styles = $self->parse_block($styles);
if (!defined($new_contents)) {
$main::lxdebug->leave_sub();
return 0;
}
- $zip->contents("styles.xml", $new_styles);
+ $zip->contents("styles.xml", Encode::encode('utf-8-strict', $new_styles));
}
$zip->writeToFileNamed($form->{"tmpfile"}, 1);
}
$form->{id} = 0;
- if ($form->{"original_accno"} &&
- ($form->{"accno"} eq $form->{"original_accno"})) {
- $form->error($locale->text('Account Number already used!'));
- }
$form->redirect($locale->text('Account saved!'))
if (AM->save_account(\%myconfig, \%$form));
$form->error($locale->text('Cannot save account!'));
$form->{"${name}_id"} = $new_id;
+ _reset_salesman_id();
IS->get_customer(\%myconfig, \%$form) if ($name eq 'customer');
IR->get_vendor(\%myconfig, \%$form) if ($name eq 'vendor');
$form->{$name} = $form->{name_list}[0]->{name};
$form->{"old$name"} = qq|$form->{$name}--$form->{"${name}_id"}|;
+ _reset_salesman_id();
IS->get_customer(\%myconfig, \%$form) if ($name eq 'customer');
IR->get_vendor(\%myconfig, \%$form) if ($name eq 'vendor');
# index for new item
my $i = $form->{ndx};
+ _reset_salesman_id();
+
$form->{ $form->{vc} } = $form->{"new_name_$i"};
$form->{"$form->{vc}_id"} = $form->{"new_id_$i"};
$form->{"old$form->{vc}"} =
$main::lxdebug->leave_sub();
}
+# Reset the $::form field 'salesman_id' to the ID of the currently
+# logged in user. Useful when changing to a customer/vendor that has
+# no salesman listed in their master data.
+sub _reset_salesman_id {
+ my $current_employee = SL::DB::Manager::Employee->current;
+ $::form->{salesman_id} = $current_employee->id if $current_employee && exists $::form->{salesman_id};
+}
+
sub check_project {
$main::lxdebug->enter_sub();
use SL::AM;
use SL::CVar;
use SL::IC;
+use SL::Helper::Flash;
use SL::ReportGenerator;
#use SL::PE;
IC->retrieve_buchungsgruppen(\%myconfig, $form);
@{ $form->{BUCHUNGSGRUPPEN} } = grep { $_->{id} eq $form->{buchungsgruppen_id} || ($form->{id} && $form->{orphaned}) || !$form->{id} } @{ $form->{BUCHUNGSGRUPPEN} };
+ if (!SL::TransNumber->new(number => $form->{partnumber}, type => $form->{item}, id => $form->{id})->is_unique) {
+ flash('info', $::locale->text('This partnumber is not unique. You should change it.'));
+ }
+
# use JavaScript Calendar or not (yes!)
$form->{jsscript} = 1;
use SL::DB::Language;
use SL::DB::Printer;
+use SL::Helper::Flash;
require "bin/mozilla/common.pl";
# check if items are valid
if ($form->{rowcount} == 1) {
+ flash('warning', $::locale->text('The action you\'ve chosen has not been executed because the document does not contain any item yet.'));
&update;
::end_of_request();
}
my $emailed = $form->{emailed};
if ($form->{media} eq 'queue') {
- my %queued = map { s|.*/|| } split / /, $form->{queued};
+ my %queued = map { s|.*[/\\]||; $_ } split / /, $form->{queued};
my $filename;
my $suffix = ($form->{postscript}) ? '.ps' : '.pdf';
if ($filename = $queued{ $form->{formname} }) {
- $form->{queued} =~ s/\Q$form->{formname} $filename\E//;
unlink $::lx_office_conf{paths}->{spool} . "/$filename";
- $filename =~ s/\..*$//g;
- $filename .= $suffix;
- $form->{OUT} = $::lx_office_conf{paths}->{spool} . "/$filename";
- $form->{OUT_MODE} = '>';
+ delete $queued{ $form->{formname} };
+
+ $form->{queued} = join ' ', %queued;
+ $filename =~ s/\..*$//g;
+ $filename .= $suffix;
+ $form->{OUT} = $::lx_office_conf{paths}->{spool} . "/$filename";
+ $form->{OUT_MODE} = '>';
+
} else {
my $temp_fh;
($temp_fh, $filename) = File::Temp::tempfile(
'kivitendo-spoolXXXXXX',
SUFFIX => "$suffix",
- DIR => $::lx_office_conf{paths}->{spool},
+ DIR => $::lx_office_conf{paths}->{spool},
+ UNLINK => 0,
);
close $temp_fh;
$form->{OUT} = "$filename";
use SL::OE;
use SL::ReportGenerator;
+use SL::DB::Part;
+
use Data::Dumper;
require "bin/mozilla/common.pl";
show_no_warehouses_error() if (!scalar @{ $form->{WAREHOUSES} });
my $units = AM->retrieve_units(\%myconfig, $form);
+
+ my $part = 0;
+ if ( $form->{parts_id} ) {
+ $part = SL::DB::Part->new();
+ $part->id($form->{parts_id});
+ $part->load();
+ }
+
# der zweite Parameter von unit_select_data gibt den default-Namen (selected) vor
- $form->{UNITS} = AM->unit_select_data($units, $form->{unit}, 0, $form->{unit});
+ $form->{UNITS} = AM->unit_select_data($units, $form->{unit}, 0, $part ? $part->unit : 0);
if (scalar @{ $form->{WAREHOUSES} }) {
$form->{warehouse_id} ||= $form->{WAREHOUSES}->[0]->{id};
'Account Link IC_taxpart' => 'Warenliste Steuer',
'Account Link IC_taxservice' => 'Dienstleistungen Steuer',
'Account Number' => 'Kontonummer',
- 'Account Number already used!' => 'Kontonummer ist bereits in Benutzung!',
'Account Number missing!' => 'Kontonummer fehlt!',
'Account Nummer' => 'Kontonummer',
'Account Type' => 'Kontoart',
'Invoice total less discount' => 'Rechnungssumme abzüglich Skonto',
'Invoice with Storno (abbreviation)' => 'R(S)',
'Invoices' => 'Rechnungen',
+ 'Invoices, Credit Notes & AR Transactions' => 'Rechnungen, Gutschriften & Debitorenbuchungen',
'Is Searchable' => 'Durchsuchbar',
'Is this a summary account to record' => 'Sammelkonto für',
'It is possible that even after such a correction there is something wrong with this transaction (e.g. taxes that don\'t match the selected taxkey). Therefore you should re-run the general ledger analysis.' => 'Auch nach einer Korrektur kann es mit dieser Buchung noch weitere Probleme geben (z.B. nicht zum Steuerschlüssel passende Steuern), weshalb ein erneutes Ausführen der Hauptbuchanalyse empfohlen wird.',
'The access rights have been saved.' => 'Die Zugriffsrechte wurden gespeichert.',
'The account 3804 already exists, the update will be skipped.' => 'Das Konto 3804 existiert schon, das Update wird übersprungen.',
'The account 3804 will not be added automatically.' => 'Das Konto 3804 wird nicht automatisch hinzugefügt.',
+ 'The action you\'ve chosen has not been executed because the document does not contain any item yet.' => 'Die von Ihnen ausgewählte Aktion wurde nicht ausgeführt, weil der Beleg noch keine Positionen enthält.',
'The application "#1" was not found on the system.' => 'Die Anwendung "#1" wurde auf dem System nicht gefunden.',
'The assembly has been created.' => 'Das Erzeugnis wurde hergestellt.',
'The assistant could not find anything wrong with #1. Maybe the problem has been solved in the meantime.' => 'Der Korrekturassistent konnte kein Problem bei #1 feststellen. Eventuell wurde das Problem in der Zwischenzeit bereits behoben.',
'This option controls the inventory system.' => 'Dieser Parameter legt die Warenbuchungsmethode fest.',
'This option controls the method used for profit determination.' => 'Dieser Parameter legt die Berechnungsmethode für die Gewinnermittlung fest.',
'This option controls the posting and calculation behavior for the accounting method.' => 'Dieser Parameter steuert die Buchungs- und Berechnungsmethoden für die Versteuerungsart.',
+ 'This partnumber is not unique. You should change it.' => 'Diese Artikelnummer ist nicht eindeutig. Bitte wählen Sie eine andere.',
'This transaction has to be split into several transactions manually.' => 'Diese Buchung muss manuell in mehrere Buchungen aufgeteilt werden.',
'This update will change the nature the onhand of goods is tracked.' => 'Dieses update ändert die Art und Weise wie Lagermengen gezält werden.',
'This upgrade script tries to map all existing parts in the database to the newly created Buchungsgruppen.' => 'Dieses Upgradescript versucht, bei allen bestehenden Artikeln neu erstellte Buchungsgruppen zuzuordnen.',
'Vendor' => 'Lieferant',
'Vendor (name)' => 'Lieferant (Name)',
'Vendor Invoice' => 'Einkaufsrechnung',
- 'Vendor Invoices' => 'Einkaufsrechnungen',
+ 'Vendor Invoices & AP Transactions' => 'Einkaufsrechnungen & Kreditorenbuchungen',
'Vendor Name' => 'Lieferantenname',
'Vendor Number' => 'Lieferantennummer',
'Vendor Order Number' => 'Bestellnummer beim Lieferanten',
'Weight unit' => 'Gewichtseinheit',
'What <b>term</b> you are looking for?' => 'Nach welchem <b>Begriff</b> wollen Sie suchen?',
'What type of item is this?' => 'Was ist dieser Artikel?',
- 'Which is located at doc/Lx-Office-Dokumentation.pdf. Click here: ' => 'Zu finden in doc/Lx-Office-Dokumentation.pdf. Oder hier klicken: ',
+ 'Which is located at doc/kivitendo-Dokumentation.pdf. Click here: ' => 'Zu finden in doc/kivitendo-Dokumentation.pdf. Oder hier klicken: ',
'With Extension Of Time' => 'mit Dauerfristverlängerung',
'Workflow Delivery Order' => 'Workflow Lieferschein',
'Workflow purchase_order' => 'Workflow Lieferantenauftrag',
action=search
type=sales_delivery_order
-[AR--Reports--Invoices]
+[AR--Reports--Invoices, Credit Notes & AR Transactions]
ACCESS=invoice_edit
module=ar.pl
action=search
action=search
type=purchase_delivery_order
-[AP--Reports--Vendor Invoices]
+[AP--Reports--Vendor Invoices & AP Transactions]
ACCESS=vendor_invoice_edit
module=ap.pl
action=search
my ($opt_list, $opt_tree, $opt_rtree, $opt_nodeps, $opt_graphviz, $opt_help);
my ($opt_user, $opt_apply, $opt_applied, $opt_unapplied, $opt_format, $opt_test_utf8);
-my ($opt_dbhost, $opt_dbport, $opt_dbname, $opt_dbuser, $opt_dbpassword);
+my ($opt_dbhost, $opt_dbport, $opt_dbname, $opt_dbuser, $opt_dbpassword, $opt_create, $opt_type);
+my ($opt_description, $opt_encoding, @opt_depends);
our (%myconfig, $form, $user, $auth, $locale, $controls, $dbupgrader);
"\n\n";
}
+sub create_upgrade {
+ my (%params) = @_;
+
+ my $filename = $params{filename};
+ my $dbupgrader = $params{dbupgrader};
+ my $type = $params{type} || '';
+ my $description = $params{description} || '';
+ my $encoding = $params{encoding} || 'utf-8';
+ my @depends = @{ $params{depends} };
+
+ if (!@depends) {
+ my @releases = grep { /^release_/ } keys %$controls;
+ @depends = ((sort @releases)[-1]);
+ }
+
+ my $comment;
+ if ($type eq 'sql') {
+ $comment = '--';
+ } elsif ($type eq 'pl') {
+ $comment = '#';
+ } elsif (!$type) {
+ die 'Error: No --type was given but is required for --create.';
+ } else {
+ die 'Error: Unknown --type. Try "sql" or "pl".';
+ }
+
+ my $full_filename = $dbupgrader->path . '/' . $filename . '.' . $type;
+
+ die "file '$full_filename' already exists, aborting" if -f $full_filename;
+
+
+ open my $fh, ">:utf8", $full_filename or die "can't open $full_filename";
+ print $fh "$comment \@tag: $filename\n";
+ print $fh "$comment \@description: $description\n";
+ print $fh "$comment \@depends: @depends\n";
+ print $fh "$comment \@encoding: $encoding\n";
+ close $fh;
+
+ system("\$EDITOR $full_filename");
+ exit 0;
+}
+
sub apply_upgrade {
my $name = shift;
"user=s" => \$opt_user,
"apply=s" => \$opt_apply,
"applied" => \$opt_applied,
+ "create=s" => \$opt_create,
+ "type=s" => \$opt_type,
+ "encoding=s" => \$opt_encoding,
+ "description=s" => \$opt_description,
+ "depends=s" => \@opt_depends,
"unapplied" => \$opt_unapplied,
"test-utf8" => \$opt_test_utf8,
"dbhost:s" => \$opt_dbhost,
dump_graphviz('file_name' => $opt_graphviz,
'format' => $opt_format) if (defined $opt_graphviz);
dump_nodeps() if ($opt_nodeps);
+create_upgrade(filename => $opt_create,
+ dbupgrader => $dbupgrader,
+ type => $opt_type,
+ description => $opt_description,
+ encoding => $opt_encoding,
+ depends => \@opt_depends) if ($opt_create);
if ($opt_user) {
$auth = SL::Auth->new();
dump_unapplied();
}
+
if ($opt_test_utf8) {
$form->error("--test-utf8 used but no database name given with --dbname.") if (!$opt_dbname);
-use Test::More tests => 41;
+use Test::More tests => 47;
use lib 't';
+use utf8;
use Data::Dumper;
-use utf8;
+use Support::TestSetup;
-use_ok 'Support::TestSetup';
use_ok 'SL::Helper::Csv';
Support::TestSetup::login();
$csv = SL::Helper::Csv->new(
file => \"Description\nKaffee",
class => 'SL::DB::Part',
+ case_insensitive_header => 1,
+ profile => { description => 'description' },
);
$csv->parse;
is_deeply $csv->get_data, [ { description => 'Kaffee' } ], 'case insensitive header from csv works';
#####
$csv = SL::Helper::Csv->new(
-file => \"Kaffee",
-header => [ 'Description' ],
-class => 'SL::DB::Part',
+ file => \"Kaffee",
+ header => [ 'Description' ],
+ class => 'SL::DB::Part',
+ case_insensitive_header => 1,
+ profile => { description => 'description' },
);
$csv->parse;
is_deeply $csv->get_data, [ { description => 'Kaffee' } ], 'case insensitive header as param works';
$csv->parse;
is_deeply $csv->get_data, [ { description => 'Kaffee' } ], 'utf8 BOM works (bug 1872)';
+#####
+
+$csv = SL::Helper::Csv->new(
+ file => \"Kaffee",
+ header => [ 'Description' ],
+ class => 'SL::DB::Part',
+);
+$csv->parse;
+is_deeply $csv->get_data, undef, 'case insensitive header without flag ignores';
+
+#####
+
+$csv = SL::Helper::Csv->new(
+ file => \"Kaffee",
+ header => [ 'foo' ],
+ class => 'SL::DB::Part',
+ profile => { foo => '' },
+);
+$csv->parse;
+
+is_deeply $csv->get_data, [ { foo => 'Kaffee' } ], 'empty path still gets parsed into data';
+ok $csv->get_objects->[0], 'empty path gets ignored in object creation';
+
+#####
+
+$csv = SL::Helper::Csv->new(
+ file => \"Kaffee",
+ header => [ 'foo' ],
+ class => 'SL::DB::Part',
+ strict_profile => 1,
+ profile => { foo => '' },
+);
+$csv->parse;
+
+is_deeply $csv->get_data, [ { foo => 'Kaffee' } ], 'empty path still gets parsed into data (strict profile)';
+ok $csv->get_objects->[0], 'empty path gets ignored in object creation (strict profile)';
+
+$csv = SL::Helper::Csv->new(
+ file => \"Phil",
+ header => [ 'CVAR_grOUnDHog' ],
+ class => 'SL::DB::Part',
+ strict_profile => 1,
+ case_insensitive_header => 1,
+ profile => { cvar_Groundhog => '' },
+);
+$csv->parse;
+
+is_deeply $csv->get_data, [ { cvar_Groundhog => 'Phil' } ], 'using empty path to get cvars working';
+ok $csv->get_objects->[0], '...and not destorying the objects';
+
# vim: ft=perl
<select name="inventory_system">
[% FOREACH row = INVENTORY_SYSTEMS %]<option value=[% HTML.escape(row.name) %] [% IF row.selected %]selected[% END %]>[% HTML.escape(row.name) | $T8 %]</option>[% END %]
</select>
- [% '* there are restrictions for the perpetual method, look at chapter "Bemerkungen zu Bestandsmethode" in' | $T8 %] <a href="doc/Lx-Office-Dokumentation.pdf">Lx-Office-Dokumentation.pdf</a>.
+ [% '* there are restrictions for the perpetual method, look at chapter "Bemerkungen zu Bestandsmethode" in' | $T8 %] <a href="doc/kivitendo-Dokumentation.pdf">kivitendo-Dokumentation.pdf</a>.
</td>
</tr>
<input type="hidden" name="type" value="account">
<input type="hidden" name="orphaned" value="[% HTML.escape(orphaned) %]">
<input type="hidden" name="new_chart_valid" value="[% HTML.escape(new_chart_valid) %]">
-<input type="hidden" name="original_accno" value="[% HTML.escape(accno) %]">
<input type="hidden" name="inventory_accno_id" value="[% HTML.escape(inventory_accno_id) %]">
<input type="hidden" name="income_accno_id" value="[% HTML.escape(income_accno_id) %]">
<input type="hidden" name="expense_accno_id" value="[% HTML.escape(expense_accno_id) %]">
<p><div class="listtop">[% title %] [% HTML.escape(partnumber) %] [% HTML.escape(description) %]</div></p>
+[% PROCESS 'common/flash.html' %]
+
<form method="post" name="ic" action="[% script %]">
<input name="id" type="hidden" value="[% HTML.escape(id) %]">
[%- HTML.escape(mainitem.title) %]
</a>
[%- IF mainitem.subitems %]
- <ul[%- IF force_ul_width %] width="[% mainitem.max_width * 12 %]"[% END %]>
+ <ul[%- IF force_ul_width %] width="[% mainitem.max_width * 10 %]"[% END %]>
[%- SET sub1_id = main_id * 100 %]
[%- FOREACH sub1item = mainitem.subitems %]
[%- SET sub1_id = sub1_id + 1 %]
[%- HTML.escape(sub1item.title) %]
</a>
[%- IF sub1item.subitems %]
- <ul[%- IF force_ul_width %] width="[% sub1item.max_width * 12 %]"[% END %]>
+ <ul[%- IF force_ul_width %] width="[% sub1item.max_width * 10 %]"[% END %]>
[%- SET sub2_id = sub1_id * 100 %]
[%- FOREACH sub2item = sub1item.subitems %]
[%- SET sub2_id = sub2_id + 1 %]