From: Moritz Bunkus Date: Sat, 28 Apr 2012 10:59:54 +0000 (+0200) Subject: Merge branch 'master' of vc.linet-services.de:public/lx-office-erp X-Git-Tag: release-3.0.0beta1~343^2 X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/mfinanz.git/commitdiff_plain/e74dac176e01090f7e3b6bd9e99596a36e614284?hp=eef9560c633d8e84cca1d96b03a711862dc8c2d6 Merge branch 'master' of vc.linet-services.de:public/lx-office-erp --- diff --git a/SL/CVar.pm b/SL/CVar.pm index 714744a1a..c0b3f43f0 100644 --- a/SL/CVar.pm +++ b/SL/CVar.pm @@ -7,7 +7,7 @@ use Scalar::Util qw(blessed); use Data::Dumper; use SL::DBUtils; -use SL::MoreCommon qw(listify); +use SL::MoreCommon qw(any listify); sub get_configs { $main::lxdebug->enter_sub(); @@ -243,6 +243,8 @@ sub get_custom_variables { : $cvar->{type} eq 'timestamp' ? $act_var->{timestamp_value} : $cvar->{type} eq 'number' ? $act_var->{number_value} : $cvar->{type} eq 'customer' ? $act_var->{number_value} + : $cvar->{type} eq 'vendor' ? $act_var->{number_value} + : $cvar->{type} eq 'part' ? $act_var->{number_value} : $cvar->{type} eq 'bool' ? $act_var->{bool_value} : $act_var->{text_value}; $cvar->{valid} = $valid; @@ -279,6 +281,12 @@ sub get_custom_variables { } elsif ($cvar->{type} eq 'customer') { require SL::DB::Customer; $cvar->{value} = SL::DB::Manager::Customer->find_by(id => $cvar->{value} * 1); + } elsif ($cvar->{type} eq 'vendor') { + require SL::DB::Vendor; + $cvar->{value} = SL::DB::Manager::Vendor->find_by(id => $cvar->{value} * 1); + } elsif ($cvar->{type} eq 'part') { + require SL::DB::Part; + $cvar->{value} = SL::DB::Manager::Part->find_by(id => $cvar->{value} * 1); } } @@ -340,7 +348,7 @@ sub save_custom_variables { } elsif ($config->{type} eq 'bool') { push @values, $value ? 't' : 'f', undef, undef, undef; - } elsif ($config->{type} eq 'customer') { + } elsif (any { $config->{type} eq $_ } qw(customer vendor part)) { push @values, undef, undef, undef, $value * 1; } @@ -498,10 +506,16 @@ sub build_filter_query { $not = 'NOT' if ($params{filter}->{$name} eq 'no'); push @sub_where, qq|COALESCE(cvar.bool_value, false) = TRUE|; - } elsif ($config->{type} eq 'customer') { + } elsif (any { $config->{type} eq $_ } qw(customer vendor part)) { next unless $params{filter}->{$name}; - push @sub_where, qq|cvar.number_value * 1 IN (SELECT id FROM customer WHERE name ILIKE ?)|; + my $table = $config->{type}; + push @sub_where, qq|cvar.number_value * 1 IN (SELECT id FROM $table WHERE name ILIKE ?)|; + push @sub_values, "%$params{filter}->{$name}%"; + } elsif ($config->{type} eq 'part') { + next unless $params{filter}->{$name}; + + push @sub_where, qq|cvar.number_value * 1 IN (SELECT id FROM parts WHERE partnumber ILIKE ?)|; push @sub_values, "%$params{filter}->{$name}%"; } @@ -577,6 +591,8 @@ sub add_custom_variables_to_report { : $cfg->{type} eq 'timestamp' ? $ref->{timestamp_value} : $cfg->{type} eq 'number' ? $form->format_amount($myconfig, $ref->{number_value} * 1, $cfg->{precision}) : $cfg->{type} eq 'customer' ? (SL::DB::Manager::Customer->find_by(id => 1*$ref->{number_value}) || SL::DB::Customer->new)->name + : $cfg->{type} eq 'vendor' ? (SL::DB::Manager::Vendor->find_by(id => 1*$ref->{number_value}) || SL::DB::Vendor->new)->name + : $cfg->{type} eq 'part' ? (SL::DB::Manager::Part->find_by(id => 1*$ref->{number_value}) || SL::DB::Part->new)->partnumber : $cfg->{type} eq 'bool' ? ($ref->{bool_value} ? $locale->text('Yes') : $locale->text('No')) : $ref->{text_value}; } diff --git a/SL/Controller/DeliveryPlan.pm b/SL/Controller/DeliveryPlan.pm new file mode 100644 index 000000000..e280a1b99 --- /dev/null +++ b/SL/Controller/DeliveryPlan.pm @@ -0,0 +1,313 @@ +package SL::Controller::DeliveryPlan; + +use strict; +use parent qw(SL::Controller::Base); + +use Clone qw(clone); +use SL::DB::OrderItem; +use SL::Controller::Helper::ParseFilter; +use SL::Controller::Helper::ReportGenerator; + +__PACKAGE__->run_before(sub { $::auth->assert('sales_order_edit'); }); + +sub action_list { + my ($self) = @_; + my %list_params = ( + sort_by => $::form->{sort_by} || 'reqdate', + sort_dir => $::form->{sort_dir}, + filter => $::form->{filter}, + page => $::form->{page}, + ); + + my $db_args = $self->setup_for_list(%list_params); + $self->{pages} = SL::DB::Manager::OrderItem->paginate(%list_params, args => $db_args); + $self->{flat_filter} = { map { $_->{key} => $_->{value} } $::form->flatten_variables('filter') }; + $self->make_filter_summary; + + my $top = $::form->parse_html_template('delivery_plan/report_top', { FORM => $::form, SELF => $self }); + my $bottom = $::form->parse_html_template('delivery_plan/report_bottom', { SELF => $self }); + + $self->prepare_report( + report_generator_options => { + raw_top_info_text => $top, + raw_bottom_info_text => $bottom, + controller_class => 'DeliveryPlan', + }, + report_generator_export_options => [ + 'list', qw(filter sort_by sort_dir), + ], + db_args => $db_args, + ); + + $self->{orderitems} = SL::DB::Manager::OrderItem->get_all(%$db_args); + + $self->list_objects; +} + +# private functions + +sub setup_for_list { + my ($self, %params) = @_; + $self->{filter} = {}; + my %args = ( + parse_filter( + $self->_pre_parse_filter($::form->{filter}, $self->{filter}), + with_objects => [ 'order', 'order.customer', 'part' ], + launder_to => $self->{filter}, + ), + sort_by => $self->set_sort_params(%params), + page => $params{page}, + ); + + $args{query} = [ @{ $args{query} || [] }, + ( + 'order.customer_id' => { gt => 0 }, + 'order.closed' => 0, + or => [ 'order.quotation' => 0, 'order.quotation' => undef ], + + # filter by shipped_qty < qty, read from innermost to outermost + 'id' => [ \" + -- 3. resolve the desired information about those + SELECT oi.id FROM ( + -- 2. slice only part, orderitem and both quantities from it + SELECT parts_id, trans_id, qty, SUM(doi_qty) AS doi_qty FROM ( + -- 1. join orderitems and deliverorder items via record_links. + -- also add customer data to filter for sales_orders + SELECT oi.parts_id, oi.trans_id, oi.id, oi.qty, doi.qty AS doi_qty + FROM orderitems oi, oe, record_links rl, delivery_order_items doi + WHERE + oe.id = oi.trans_id AND + oe.customer_id IS NOT NULL AND + (oe.quotation = 'f' OR oe.quotation IS NULL) AND + NOT oe.closed AND + rl.from_id = oe.id AND + rl.from_id = oi.trans_id AND + oe.id = oi.trans_id AND + rl.from_table = 'oe' AND + rl.to_table = 'delivery_orders' AND + rl.to_id = doi.delivery_order_id AND + oi.parts_id = doi.parts_id + ) tuples GROUP BY parts_id, trans_id, qty + ) partials + LEFT JOIN orderitems oi ON partials.parts_id = oi.parts_id AND partials.trans_id = oi.trans_id + WHERE oi.qty > doi_qty + + UNION ALL + + -- 4. since the join over record_links fails for sales_orders wihtout any delivery order + -- retrieve those without record_links at all + SELECT oi.id FROM orderitems oi, oe + WHERE + oe.id = oi.trans_id AND + oe.customer_id IS NOT NULL AND + (oe.quotation = 'f' OR oe.quotation IS NULL) AND + NOT oe.closed AND + oi.trans_id NOT IN ( + SELECT from_id + FROM record_links rl + WHERE + rl.from_table ='oe' AND + rl.to_table = 'delivery_orders' + ) + " ], + ) + ]; + + return \%args; +} + +sub set_sort_params { + my ($self, %params) = @_; + my $sort_str; + ($self->{sort_by}, $self->{sort_dir}, $sort_str) = + SL::DB::Manager::OrderItem->make_sort_string(%params); + return $sort_str; +} + +sub prepare_report { + my ($self, %params) = @_; + + my $objects = $params{objects} || []; + my $report = SL::ReportGenerator->new(\%::myconfig, $::form); + $self->{report} = $report; + + my @columns = qw(reqdate customer ordnumber partnumber description qty shipped_qty); + my @visible = qw(reqdate partnumber description qty shipped_qty ordnumber customer); + my @sortable = qw(reqdate partnumber description ordnumber customer); + + my %column_defs = ( + reqdate => { text => $::locale->text('Reqdate'), + sub => sub { $_[0]->reqdate_as_date || $_[0]->order->reqdate_as_date }}, + description => { text => $::locale->text('Description'), + sub => sub { $_[0]->description }, + obj_link => sub { $self->link_to($_[0]->part) }}, + partnumber => { text => $::locale->text('Part Number'), + sub => sub { $_[0]->part->partnumber }, + obj_link => sub { $self->link_to($_[0]->part) }}, + qty => { text => $::locale->text('Qty'), + sub => sub { $_[0]->qty_as_number . ' ' . $_[0]->unit }}, + missing => { text => $::locale->text('Missing qty'), + sub => sub { $::form->format_amount(\%::myconfig, $_[0]->qty - $_[0]->shipped_qty, 2) . ' ' . $_[0]->unit }}, + shipped_qty => { text => $::locale->text('shipped'), + sub => sub { $::form->format_amount(\%::myconfig, $_[0]->shipped_qty, 2) . ' ' . $_[0]->unit }}, + ordnumber => { text => $::locale->text('Order'), + sub => sub { $_[0]->order->ordnumber }, + obj_link => sub { $self->link_to($_[0]->order) }}, + customer => { text => $::locale->text('Customer'), + sub => sub { $_[0]->order->customer->name }, + obj_link => sub { $self->link_to($_[0]->order->customer) }}, + ); + + + for my $col (@sortable) { + $column_defs{$col}{link} = $self->url_for( + action => 'list', + sort_by => $col, + sort_dir => ($self->{sort_by} eq $col ? 1 - $self->{sort_dir} : $self->{sort_dir}), + page => $self->{pages}{cur}, + %{ $self->{flat_filter} }, + ); + } + + map { $column_defs{$_}->{visible} = 1 } @visible; + + $report->set_columns(%column_defs); + $report->set_column_order(@columns); + $report->set_options(allow_pdf_export => 1, allow_csv_export => 1); + $report->set_sort_indicator(%params); + $report->set_export_options(@{ $params{report_generator_export_options} || [] }); + $report->set_options( + %{ $params{report_generator_options} || {} }, + output_format => 'HTML', + top_info_text => $::locale->text('Delivery Plan for currently outstanding sales orders'), + title => $::locale->text('Delivery Plan'), + ); + $report->set_options_from_form; + + SL::DB::Manager::OrderItem->disable_paginating(args => $params{db_args}) if $report->{options}{output_format} =~ /^(pdf|csv)$/i; + + $self->{report_data} = { + column_defs => \%column_defs, + columns => \@columns, + visible => \@visible, + sortable => \@sortable, + }; +} + +sub list_objects { + my ($self) = @_; + my $column_defs = $self->{report_data}{column_defs}; + for my $obj (@{ $self->{orderitems} || [] }) { + $self->{report}->add_data({ + map { + $_ => { + data => $column_defs->{$_}{sub} ? $column_defs->{$_}{sub}->($obj) + : $obj->can($_) ? $obj->$_ + : $obj->{$_}, + link => $column_defs->{$_}{obj_link} ? $column_defs->{$_}{obj_link}->($obj) : '', + }, + } @{ $self->{report_data}{columns} || {} } + }); + } + + return $self->{report}->generate_with_headers; +} + +sub make_filter_summary { + my ($self) = @_; + + my $filter = $::form->{filter} || {}; + my @filter_strings; + + my @filters = ( + [ $filter->{order}{"ordnumber:substr::ilike"}, $::locale->text('Number') ], + [ $filter->{part}{"partnumber:substr::ilike"}, $::locale->text('Part Number') ], + [ $filter->{"description:substr::ilike"}, $::locale->text('Part Description') ], + [ $filter->{"reqdate:date::ge"}, $::locale->text('Delivery Date') . " " . $::locale->text('From Date') ], + [ $filter->{"reqdate:date::le"}, $::locale->text('Delivery Date') . " " . $::locale->text('To Date') ], + [ $filter->{"qty:number"}, $::locale->text('Quantity') ], + [ $filter->{order}{customer}{"name:substr::ilike"}, $::locale->text('Customer') ], + [ $filter->{order}{customer}{"customernumber:substr::ilike"}, $::locale->text('Customer Number') ], + ); + + my @flags = ( + [ $filter->{part}{type}{part}, $::locale->text('Parts') ], + [ $filter->{part}{type}{service}, $::locale->text('Services') ], + [ $filter->{part}{type}{assembly}, $::locale->text('Assemblies') ], + ); + + for (@flags) { + push @filter_strings, "$_->[1]" if $_->[0]; + } + for (@filters) { + push @filter_strings, "$_->[1]: $_->[0]" if $_->[0]; + } + + $self->{filter_summary} = join ', ', @filter_strings; +} + +sub link_to { + my ($self, $object, %params) = @_; + + return unless $object; + my $action = $params{action} || 'edit'; + + if ($object->isa('SL::DB::Order')) { + my $type = $object->type; + my $vc = $object->is_sales ? 'customer' : 'vendor'; + my $id = $object->id; + + return "oe.pl?action=$action&type=$type&vc=$vc&id=$id"; + } + if ($object->isa('SL::DB::Part')) { + my $id = $object->id; + return "ic.pl?action=$action&id=$id"; + } + if ($object->isa('SL::DB::Customer')) { + my $id = $object->id; + return "ct.pl?action=$action&id=$id&db=customer"; + } +} + +# unfortunately ParseFilter can't handle compount filters. +# so we clone the original filter (still need that for serializing) +# rip out the options we know an replace them with the compound options. +# ParseFilter will take care of the prefixing then. +sub _pre_parse_filter { + my ($self, $orig_filter, $launder_to) = @_; + + return undef unless $orig_filter; + + my $filter = clone($orig_filter); + if ($filter->{part} && $filter->{part}{type}) { + $launder_to->{part}{type} = delete $filter->{part}{type}; + my @part_filters = grep $_, map { + $launder_to->{part}{type}{$_} ? SL::DB::Manager::Part->type_filter($_) : () + } qw(part service assembly); + + push @{ $filter->{and} }, or => [ @part_filters ] if @part_filters; + } + + for my $op (qw(le ge)) { + if ($filter->{"reqdate:date::$op"}) { + $launder_to->{"reqdate_date__$op"} = delete $filter->{"reqdate:date::$op"}; + my $parsed_date = DateTime->from_lxoffice($launder_to->{"reqdate_date__$op"}); + push @{ $filter->{and} }, or => [ + 'reqdate' => { $op => $parsed_date }, + and => [ + 'reqdate' => undef, + 'order.reqdate' => { $op => $parsed_date }, + ] + ] if $parsed_date; + } + } + + if (my $style = delete $filter->{searchstyle}) { + $self->{searchstyle} = $style; + $launder_to->{searchstyle} = $style; + } + + return $filter; +} + +1; diff --git a/SL/Controller/Helper/ParseFilter.pm b/SL/Controller/Helper/ParseFilter.pm index 7c393b01c..3bf1b6595 100644 --- a/SL/Controller/Helper/ParseFilter.pm +++ b/SL/Controller/Helper/ParseFilter.pm @@ -20,11 +20,13 @@ my %filters = ( ); my %methods = ( - lt => sub { +{ lt => $_[0] } }, - gt => sub { +{ gt => $_[0] } }, - ilike => sub { +{ ilike => $_[0] } }, - like => sub { +{ like => $_[0] } }, enable => sub { ;;;; }, + map { + # since $_ is an alias it can't be used in a closure. even "".$_ or "$_" + # does not work, we need a real copy. + my $_copy = "$_"; + $_ => sub { +{ $_copy => $_[0] } }, + } qw(similar match imatch regex regexp like ilike rlike is is_not ne eq lt gt le ge), ); sub parse_filter { diff --git a/SL/DB/OrderItem.pm b/SL/DB/OrderItem.pm index d193393bb..f24abcaf1 100644 --- a/SL/DB/OrderItem.pm +++ b/SL/DB/OrderItem.pm @@ -68,11 +68,12 @@ sub _sort_spec { qty => [ 'qty' ], ordnumber => [ 'order.ordnumber' ], customer => [ 'lower(customer.name)', ], - position => [ 'trans_id' ], - reqdate => [ 'COALESCE(orderitems.reqdate, order.transdate)' ], + position => [ 'trans_id', 'runningnumber' ], + reqdate => [ 'COALESCE(orderitems.reqdate, order.reqdate)' ], orddate => [ 'order.orddate' ], sellprice => [ 'sellprice' ], discount => [ 'discount' ], + transdate => [ 'transdate::date', 'order.reqdate' ], }, default => [ 'position', 1 ], nulls => { } diff --git a/SL/InstallationCheck.pm b/SL/InstallationCheck.pm index 3100ac67f..935d131cd 100644 --- a/SL/InstallationCheck.pm +++ b/SL/InstallationCheck.pm @@ -11,6 +11,7 @@ BEGIN { @required_modules = ( { name => "parent", url => "http://search.cpan.org/~corion/", debian => 'libparent-perl' }, { name => "Archive::Zip", version => '1.16', url => "http://search.cpan.org/~adamk/", debian => 'libarchive-zip-perl' }, + { name => "Clone", url => "http://search.cpan.org/~rdf/", debian => 'libclone-perl' }, { name => "Config::Std", url => "http://search.cpan.org/~dconway/", debian => 'libconfig-std-perl' }, { name => "DateTime", url => "http://search.cpan.org/~drolsky/", debian => 'libdatetime-perl' }, { name => "DBI", version => '1.50', url => "http://search.cpan.org/~timb/", debian => 'libdbi-perl' }, @@ -36,6 +37,8 @@ BEGIN { @optional_modules = ( { name => "Digest::SHA", url => "http://search.cpan.org/~mshelor/", debian => 'libdigest-sha-perl' }, + { name => "IO::Socket::SSL", url => "http://search.cpan.org/~sullr/", debian => 'libio-socket-ssl-perl' }, + { name => "Net::LDAP", url => "http://search.cpan.org/~gbarr/", debian => 'libnet-ldap-perl' }, ); @developer_modules = ( @@ -97,7 +100,7 @@ my %conditional_dependencies; sub check_for_conditional_dependencies { return if $conditional_dependencies{net_ldap}++; - push @required_modules, { 'name' => 'Net::LDAP', 'url' => 'http://search.cpan.org/~gbarr/' } + push @required_modules, grep { $_->{name} eq 'Net::LDAP' } @optional_modules if $::lx_office_conf{authentication} && ($::lx_office_conf{authentication}->{module} eq 'LDAP'); } diff --git a/SL/LxOfficeConf.pm b/SL/LxOfficeConf.pm index 51ad991d9..3cd462cff 100644 --- a/SL/LxOfficeConf.pm +++ b/SL/LxOfficeConf.pm @@ -2,27 +2,51 @@ package SL::LxOfficeConf; use strict; -use Config::Std; -use Encode; - my $environment_initialized; +sub safe_require { + my ($class, $may_fail); + my $failed; + $failed = !eval { + require Config::Std; + require Encode; + }; + + if ($failed) { + if ($may_fail) { + warn $@; + return 0; + } else { + die $@; + } + } + + Config::Std->import; + Encode->import; + + return 1; +} + sub read { - my ($class, $file_name) = @_; + my ($class, $file_name, $may_fail) = @_; - read_config 'config/lx_office.conf.default' => %::lx_office_conf; + return unless $class->safe_require($may_fail); + + read_config('config/lx_office.conf.default' => \%::lx_office_conf); _decode_recursively(\%::lx_office_conf); $file_name ||= 'config/lx_office.conf'; if (-f $file_name) { - read_config $file_name => my %local_conf; + read_config($file_name => \ my %local_conf); _decode_recursively(\%local_conf); _flat_merge(\%::lx_office_conf, \%local_conf); } _init_environment(); _determine_application_paths(); + + return 1; } sub _decode_recursively { diff --git a/SL/Template/Plugin/L.pm b/SL/Template/Plugin/L.pm index f7ffc11b2..0b4967d34 100644 --- a/SL/Template/Plugin/L.pm +++ b/SL/Template/Plugin/L.pm @@ -342,6 +342,36 @@ autocomplete_customer('#$name_e\_name'); JS } +# simple version with select_tag +sub vendor_selector { + my ($self, $name, $value, %params) = @_; + + my $actual_vendor_id = (defined $::form->{"$name"})? ((ref $::form->{"$name"}) ? $::form->{"$name"}->id : $::form->{"$name"}) : + (ref $value && $value->can('id')) ? $value->id : ''; + my $options_str = $self->options_for_select(SL::DB::Manager::Vendor->get_all(), + default => $actual_vendor_id, + title_sub => sub { $_[0]->vendornumber . " : " . $_[0]->name }, + 'with_empty' => 1); + + return $self->select_tag($name, $options_str, %params); +} + + +# simple version with select_tag +sub part_selector { + my ($self, $name, $value, %params) = @_; + + my $actual_part_id = (defined $::form->{"$name"})? ((ref $::form->{"$name"})? $::form->{"$name"}->id : $::form->{"$name"}) : + (ref $value && $value->can('id')) ? $value->id : ''; + my $options_str = $self->options_for_select(SL::DB::Manager::Part->get_all(), + default => $actual_part_id, + title_sub => sub { $_[0]->partnumber . " : " . $_[0]->description }, + 'with_empty' => 1); + + return $self->select_tag($name, $options_str, %params); +} + + sub javascript_tag { my $self = shift; my $code = ''; diff --git a/bin/mozilla/amcvar.pl b/bin/mozilla/amcvar.pl index 25e3ec738..343350a24 100644 --- a/bin/mozilla/amcvar.pl +++ b/bin/mozilla/amcvar.pl @@ -55,9 +55,11 @@ our %translations = ('text' => $locale->text('Free-form text'), 'bool' => $locale->text('Yes/No (Checkbox)'), 'select' => $locale->text('Selection'), 'customer' => $locale->text('Customer'), + 'vendor' => $locale->text('Vendor'), + 'part' => $locale->text('Part'), ); -our @types = qw(text textfield number date bool select customer); # timestamp +our @types = qw(text textfield number date bool select customer vendor part); # timestamp our @modules = ({ module => 'CT', description => $locale->text('Customers and vendors') }, { module => 'Contacts', description => $locale->text('Contact persons') }, diff --git a/bin/mozilla/ct.pl b/bin/mozilla/ct.pl index 01bf4fe85..56fad897f 100644 --- a/bin/mozilla/ct.pl +++ b/bin/mozilla/ct.pl @@ -115,7 +115,6 @@ sub search_contact { $::lxdebug->enter_sub; $::auth->assert('customer_vendor_edit'); - $::form->{CUSTOM_VARIABLES} = CVar->get_configs('module' => 'Contacts'); ($::form->{CUSTOM_VARIABLES_FILTER_CODE}, $::form->{CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables' => $::form->{CUSTOM_VARIABLES}, @@ -123,6 +122,7 @@ sub search_contact { 'filter_prefix' => 'filter.', 'include_value' => 'Y'); + $::form->{title} = $::locale->text('Search contacts'); $::form->header; print $::form->parse_html_template('ct/search_contact'); @@ -329,8 +329,8 @@ sub list_contacts { 'cp_street' => { 'text' => $::locale->text('Street'), }, 'cp_phone1' => { 'text' => $::locale->text('Phone1'), }, 'cp_phone2' => { 'text' => $::locale->text('Phone2'), }, - 'cp_mobile1' => { 'text' => $::locale->text('Mobile 1'), }, - 'cp_mobile2' => { 'text' => $::locale->text('Mobile 2'), }, + 'cp_mobile1' => { 'text' => $::locale->text('Mobile1'), }, + 'cp_mobile2' => { 'text' => $::locale->text('Mobile2'), }, 'cp_email' => { 'text' => $::locale->text('E-mail'), }, 'cp_abteilung' => { 'text' => $::locale->text('Department'), }, 'cp_birthday' => { 'text' => $::locale->text('Birthday'), }, diff --git a/bin/mozilla/ic.pl b/bin/mozilla/ic.pl index 0b607da1d..3eb67383c 100644 --- a/bin/mozilla/ic.pl +++ b/bin/mozilla/ic.pl @@ -1335,9 +1335,16 @@ sub generate_report { # set module stuff if ($ref->{module} eq 'oe') { - my $edit_oe_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{cv} eq 'vendor' ? 'purchase_order' : 'sales_order'), 'id=' . E($ref->{trans_id}), 'callback'); - $row->{ordnumber}{link} = $edit_oe_link; - $row->{quonumber}{link} = $edit_oe_link if (!$ref->{ordnumber}); + # für oe gibt es vier fälle, jeweils nach kunde oder lieferant unterschiedlich: + # + # | ist bestellt | Vom Kunde bestellt | -> edit_oe_ord_link + # | Anfrage | Angebot | -> edit_oe_quo_link + + my $edit_oe_ord_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{cv} eq 'vendor' ? 'purchase_order' : 'sales_order'), 'id=' . E($ref->{trans_id}), 'callback'); + my $edit_oe_quo_link = build_std_url("script=oe.pl", 'action=edit', 'type=' . E($ref->{cv} eq 'vendor' ? 'request_quotation' : 'sales_quotation'), 'id=' . E($ref->{trans_id}), 'callback'); + + $row->{ordnumber}{link} = $edit_oe_ord_link; + $row->{quonumber}{link} = $edit_oe_quo_link if (!$ref->{ordnumber}); } else { $row->{invnumber}{link} = build_std_url("script=$ref->{module}.pl", 'action=edit', 'type=invoice', 'id=' . E($ref->{trans_id}), 'callback'); diff --git a/locale/de/all b/locale/de/all index 9e595516c..7b16fc0f0 100644 --- a/locale/de/all +++ b/locale/de/all @@ -208,6 +208,7 @@ $self->{texts} = { 'Article type (see below)' => 'Artikeltyp (siehe unten)', 'As a result, the saved onhand values of the present goods can be stored into a warehouse designated by you, or will be reset for a proper warehouse tracking' => 'Als Konsequenz können die gespeicherten Mengen entweder in ein Lager überführt werden, oder für eine frische Lagerverwaltung resettet werden.', 'Assemblies' => 'Erzeugnisse', + 'Assembly' => 'Erzeugnis', 'Assembly Description' => 'Erzeugnis-Beschreibung', 'Assembly Number' => 'Erzeugnis-Nummer', 'Assembly Number missing!' => 'Erzeugnisnummer fehlt!', @@ -592,6 +593,11 @@ $self->{texts} = { 'Delivery Order created' => 'Lieferschein erstellt', 'Delivery Order deleted!' => 'Lieferschein gelöscht!', 'Delivery Orders' => 'Lieferscheine', + 'Delivery Orders for this document' => 'Lieferscheine für dieses Dokument', + 'Delivery Plan' => 'Lieferplan', + 'Delivery Plan for currently outstanding sales orders' => 'Lieferplan für offene Verkaufsaufträge', + 'Delivery information deleted.' => 'Lieferinformation gelöscht.', + 'Delivery information saved.' => 'Lieferinformation gespeichert.', 'Department' => 'Abteilung', 'Department 1' => 'Abteilung (1)', 'Department 2' => 'Abteilung (2)', @@ -903,6 +909,7 @@ $self->{texts} = { 'Help Template Variables' => 'Hilfe zu Dokumenten-Variablen', 'Help on column names' => 'Hilfe zu Spaltennamen', 'Here\'s an example command line:' => 'Hier ist eine Kommandozeile, die als Beispiel dient:', + 'Hide Filter' => 'Filter verbergen', 'Hide by default' => 'Standardmäßig verstecken', 'Hide help text' => 'Hilfetext verbergen', 'History' => 'Historie', @@ -1140,10 +1147,8 @@ $self->{texts} = { 'Mitarbeiter' => 'Mitarbeiter', 'Mixed (requires column "type")' => 'Gemischt (erfordert Spalte "type")', 'Mobile' => 'Mobiltelefon', - 'Mobile 1' => '', - 'Mobile 2' => '', - 'Mobile1' => 'Mobile 1', - 'Mobile2' => 'Mobile 2', + 'Mobile1' => 'Mobil 1', + 'Mobile2' => 'Mobil 2', 'Model' => 'Lieferanten-Art-Nr.', 'Model (with X being a number)' => 'Lieferanten-Art-Nr. (X ist eine fortlaufende Zahl)', 'Module' => 'Modul', @@ -1520,6 +1525,7 @@ $self->{texts} = { 'Requested execution date from' => 'Gewünschtes Ausführungsdatum von', 'Requested execution date to' => 'Gewünschtes Ausführungsdatum bis', 'Required by' => 'Lieferdatum', + 'Reset' => 'Zurücksetzen', 'Restore Dataset' => 'Datenbank wiederherstellen', 'Revenue' => 'Erlöskonto', 'Revenue Account' => 'Erlöskonto', @@ -1637,6 +1643,7 @@ $self->{texts} = { 'Shopartikel' => 'Shopartikel', 'Short' => 'Knapp', 'Show' => 'Zeigen', + 'Show Filter' => 'Filter zeigen', 'Show Salesman' => 'Verkäufer anzeigen', 'Show TODO list' => 'Aufgabenliste anzeigen', 'Show by default' => 'Standardmäßig anzeigen', diff --git a/locale/de_DE/all b/locale/de_DE/all index df19dbaaf..8d090b85d 100644 --- a/locale/de_DE/all +++ b/locale/de_DE/all @@ -1144,8 +1144,9 @@ $self->{texts} = { 'Missing user id!' => 'Benutzer ID fehlt!', 'Mitarbeiter' => 'Mitarbeiter', 'Mixed (requires column "type")' => 'Gemischt (erfordert Spalte "type")', - 'Mobile1' => 'Mobile 1', - 'Mobile2' => 'Mobile 2', + 'Mobile' => 'Mobiltelefon', + 'Mobile1' => 'Mobil 1', + 'Mobile2' => 'Mobil 2', 'Model' => 'Lieferanten-Art-Nr.', 'Model (with X being a number)' => 'Lieferanten-Art-Nr. (X ist eine fortlaufende Zahl)', 'Module' => 'Modul', diff --git a/menu.ini b/menu.ini index da5450664..ac8f9b9b1 100644 --- a/menu.ini +++ b/menu.ini @@ -166,6 +166,10 @@ ACCESS=dunning_edit module=dn.pl action=search +[AR--Reports--Delivery Plan] +ACCESS=sales_order_edit +module=controller.pl +action=DeliveryPlan/list [AP] diff --git a/scripts/installation_check.pl b/scripts/installation_check.pl index def85906c..a50d184d2 100755 --- a/scripts/installation_check.pl +++ b/scripts/installation_check.pl @@ -14,6 +14,7 @@ BEGIN { } use SL::InstallationCheck; +use SL::LxOfficeConf; my %check; Getopt::Long::Configure ("bundling"); @@ -47,6 +48,12 @@ if ($check{a}) { $| = 1; +if (!SL::LxOfficeConf->read(undef, 'may fail')) { + print_header('Could not load the config file. If you have dependancies from any features enabled in the configuration these will still show up as optional because of this. Please rerun this script after installing the dependancies needed to load the cofiguration.') +} else { + SL::InstallationCheck::check_for_conditional_dependencies(); +} + if ($check{r}) { print_header('Checking Required Modules'); check_module($_, required => 1) for @SL::InstallationCheck::required_modules; diff --git a/templates/webpages/amcvar/render_inputs.html b/templates/webpages/amcvar/render_inputs.html index a69101bf0..dc9c09fe8 100644 --- a/templates/webpages/amcvar/render_inputs.html +++ b/templates/webpages/amcvar/render_inputs.html @@ -27,6 +27,12 @@ [%- ELSIF var.type == 'customer' %] [% L.customer_picker(var_name, var.value) %] +[%- ELSIF var.type == 'vendor' %] +[% L.vendor_selector(var_name, var.value) %] + +[%- ELSIF var.type == 'part' %] +[% L.part_selector(var_name, var.value) %] + [%- ELSIF var.type == 'select' %]