use parent qw(SL::Controller::Base);
+use SL::Controller::Helper::GetModels;
+use SL::Controller::Helper::Paginated;
+use SL::Controller::Helper::Sorted;
use SL::DB::BackgroundJob;
use SL::Helper::Flash;
use SL::System::TaskServer;
use Rose::Object::MakeMethods::Generic
(
scalar => [ qw(background_job) ],
- 'scalar --get_set_init' => [ qw(task_server) ],
+ 'scalar --get_set_init' => [ qw(task_server back_to) ],
);
__PACKAGE__->run_before('check_auth');
__PACKAGE__->run_before('check_task_server');
__PACKAGE__->run_before('load_background_job', only => [ qw(edit update destroy execute) ]);
+__PACKAGE__->make_paginated(ONLY => [ qw(list) ]);
+
+__PACKAGE__->make_sorted(
+ ONLY => [ qw(list) ],
+
+ package_name => $::locale->text('Package name'),
+ type => $::locale->text('Execution type'),
+ active => $::locale->text('Active'),
+ cron_spec => $::locale->text('Execution schedule'),
+ last_run_at => $::locale->text('Last run at'),
+ next_run_at => $::locale->text('Next run at'),
+);
+
#
# actions
#
$self->render('background_job/list',
title => $::locale->text('Background jobs'),
- BACKGROUND_JOBS => SL::DB::Manager::BackgroundJob->get_all_sorted);
+ BACKGROUND_JOBS => $self->get_models);
}
sub action_new {
flash_later('error', $::locale->text('The background job could not be destroyed.'));
}
- $self->redirect_to(action => 'list');
+ $self->redirect_to($self->back_to);
}
sub action_save_and_execute {
flash_later('info', $is_new ? $::locale->text('The background job has been created.') : $::locale->text('The background job has been saved.'));
return if $return;
- $self->redirect_to(action => 'list');
+ $self->redirect_to($self->back_to);
}
sub load_background_job {
flash('warning', $::locale->text('The task server does not appear to be running.')) if !$self->task_server->is_running;
}
+sub init_back_to {
+ my ($self) = @_;
+ return $::form->{back_to} || $self->url_for(action => 'list');
+}
+
1;
use parent qw(SL::Controller::Base);
use SL::Controller::Helper::GetModels;
+use SL::Controller::Helper::Paginated;
use SL::Controller::Helper::Sorted;
use SL::DB::BackgroundJobHistory;
use SL::Helper::Flash;
__PACKAGE__->run_before('add_stylesheet');
__PACKAGE__->run_before('check_task_server');
+__PACKAGE__->make_paginated(ONLY => [ qw(list) ]);
+
__PACKAGE__->make_sorted(
ONLY => [ qw(list) ],
}
sub _controller_name {
- return (split(/::/, ref($_[0]) || $_[0]))[-1];
+ my $class = ref($_[0]) || $_[0];
+ $class =~ s/^SL::Controller:://;
+ return $class;
}
sub _dispatch {
use Exporter qw(import);
our @EXPORT = qw(get_callback get_models);
-my $current_action;
+use constant PRIV => '__getmodelshelperpriv';
+
my %registered_handlers = ( callback => [], get_models => [] );
sub register_get_models_handlers {
$only = [ $only ] if !ref $only;
my %hook_params = @{ $only } ? ( only => $only ) : ();
- $class->run_before(sub { $current_action = $_[1]; }, %hook_params);
+ $class->run_before(sub { $_[0]->{PRIV()} = { current_action => $_[1] }; }, %hook_params);
map { push @{ $registered_handlers{$_} }, $additional_handlers{$_} if $additional_handlers{$_} } keys %registered_handlers;
}
sub get_callback {
my ($self, %override_params) = @_;
- my %default_params = _run_handlers($self, 'callback', action => $current_action);
+ my %default_params = _run_handlers($self, 'callback', action => ($self->{PRIV()} || {})->{current_action});
return $self->url_for(%default_params, %override_params);
}
--- /dev/null
+package SL::Controller::Helper::Paginated;
+
+use strict;
+
+use Exporter qw(import);
+our @EXPORT = qw(make_paginated get_paginate_spec get_current_paginate_params _save_current_paginate_params _get_models_handler_for_paginated _callback_handler_for_paginated);
+
+use constant PRIV => '__paginatedhelper_priv';
+
+my $controller_paginate_spec;
+
+sub make_paginated {
+ my ($class, %specs) = @_;
+
+ $specs{MODEL} ||= $class->_controller_name;
+ $specs{MODEL} =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
+ $specs{PER_PAGE} ||= "SL::DB::Manager::$specs{MODEL}"->default_objects_per_page;
+ $specs{FORM_PARAMS} ||= [ qw(page per_page) ];
+ $specs{ONLY} ||= [];
+ $specs{ONLY} = [ $specs{ONLY} ] if !ref $specs{ONLY};
+
+ $controller_paginate_spec = \%specs;
+
+ my %hook_params = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
+ $class->run_before('_save_current_paginate_params', %hook_params);
+
+ SL::Controller::Helper::GetModels::register_get_models_handlers(
+ $class,
+ callback => '_callback_handler_for_paginated',
+ get_models => '_get_models_handler_for_paginated',
+ ONLY => $specs{ONLY},
+ );
+
+ # $::lxdebug->dump(0, "CONSPEC", \%specs);
+}
+
+sub get_paginate_spec {
+ my ($class_or_self) = @_;
+
+ return $controller_paginate_spec;
+}
+
+sub get_current_paginate_params {
+ my ($self, %params) = @_;
+
+ my $spec = $self->get_paginate_spec;
+
+ my $priv = $self->{PRIV()} || {};
+ $params{page} = $priv->{page} unless defined $params{page};
+ $params{per_page} = $priv->{per_page} unless defined $params{per_page};
+
+ my %paginate_params = (
+ page => ($params{page} * 1) || 1,
+ per_page => ($params{per_page} * 1) || $spec->{PER_PAGE},
+ );
+
+ my $calculated_params = "SL::DB::Manager::$spec->{MODEL}"->paginate(%paginate_params, args => {});
+ %paginate_params = (
+ %paginate_params,
+ num_pages => $calculated_params->{max},
+ common_pages => $calculated_params->{common},
+ );
+
+ # $::lxdebug->dump(0, "get_current_paginate_params: ", \%paginate_params);
+
+ return %paginate_params;
+}
+
+#
+# private functions
+#
+
+sub _save_current_paginate_params {
+ my ($self) = @_;
+
+ my $paginate_spec = $self->get_paginate_spec;
+ $self->{PRIV()} = {
+ page => $::form->{ $paginate_spec->{FORM_PARAMS}->[0] } || 1,
+ per_page => $::form->{ $paginate_spec->{FORM_PARAMS}->[1] } * 1,
+ };
+
+ # $::lxdebug->message(0, "saving current paginate params to " . $self->{PRIV()}->{page} . ' / ' . $self->{PRIV()}->{per_page});
+}
+
+sub _callback_handler_for_paginated {
+ my ($self, %params) = @_;
+ my $priv = $self->{PRIV()} || {};
+
+ if ($priv->{page}) {
+ my $paginate_spec = $self->get_paginate_spec;
+ $params{ $paginate_spec->{FORM_PARAMS}->[0] } = $priv->{page};
+ $params{ $paginate_spec->{FORM_PARAMS}->[1] } = $priv->{per_page} if $priv->{per_page};
+ }
+
+ # $::lxdebug->dump(0, "CB handler for paginated; params nach modif:", \%params);
+
+ return %params;
+}
+
+sub _get_models_handler_for_paginated {
+ my ($self, %params) = @_;
+ $params{model} ||= $self->get_paginate_spec->{MODEL};
+
+ "SL::DB::Manager::$params{model}"->paginate($self->get_current_paginate_params, args => \%params);
+
+ # $::lxdebug->dump(0, "GM handler for paginated; params nach modif:", \%params);
+
+ return %params;
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Controller::Helper::Paginated - A helper for semi-automatic handling
+of paginating lists of database models in a controller
+
+=head1 SYNOPSIS
+
+In a controller:
+
+ use SL::Controller::Helper::GetModels;
+ use SL::Controller::Helper::Paginated;
+
+ __PACKAGE__->make_paginated(
+ MODEL => 'BackgroundJobHistory',
+ ONLY => [ qw(list) ],
+ FORM_PARAMS => [ qw(page per_page) ],
+ );
+
+ sub action_list {
+ my ($self) = @_;
+
+ my $paginated_models = $self->get_models;
+ $self->render('controller/list', ENTRIES => $paginated_models);
+ }
+
+In said template:
+
+ [% USE L %]
+
+ <table>
+ <thead>
+ <tr>
+ ...
+ </tr>
+ </thead>
+
+ <tbody>
+ [% FOREACH entry = ENTRIES %]
+ <tr>
+ ...
+ </tr>
+ [% END %]
+ </tbody>
+ </table>
+
+ [% L.paginate_controls %]
+
+=head1 OVERVIEW
+
+This specialized helper module enables controllers to display a
+paginatable list of database models with as few lines as possible. It
+can also be combined trivially with the L<SL::Controller::Sorted>
+helper for sortable lists.
+
+For this to work the controller has to provide the information which
+indexes are eligible for paginateing etc. by a call to
+L<make_paginated> at compile time.
+
+The underlying functionality that enables the use of more than just
+the paginate helper is provided by the controller helper
+C<GetModels>. See the documentation for L<SL::Controller::Sorted> for
+more information on it.
+
+A template can use the method C<paginate_controls> from the layout
+helper module C<L> which renders the links for navigation between the
+pages.
+
+This module requires that the Rose model managers use their C<Paginated>
+helper.
+
+The C<Paginated> helper hooks into the controller call to the action via
+a C<run_before> hook. This is done so that it can remember the paginate
+parameters that were used in the current view.
+
+=head1 PACKAGE FUNCTIONS
+
+=over 4
+
+=item C<make_paginated %paginate_spec>
+
+This function must be called by a controller at compile time. It is
+uesd to set the various parameters required for this helper to do its
+magic.
+
+The hash C<%paginate_spec> can include the following parameters:
+
+=over 4
+
+=item * C<MODEL>
+
+Optional. A string: the name of the Rose database model that is used
+as a default in certain cases. If this parameter is missing then it is
+derived from the controller's package (e.g. for the controller
+C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
+C<BackgroundJobHistory>).
+
+=item * C<PER_PAGE>
+
+Optional. An integer: the number of models to return per page.
+
+Defaults to the underlying database model's default number of models
+per page.
+
+=item * C<FORM_PARAMS>
+
+Optional. An array reference with exactly two strings that name the
+indexes in C<$::form> in which the current page's number (the first
+element in the array) and the number of models per page (the second
+element in the array) are stored.
+
+Defaults to the values C<page> and C<per_page> if missing.
+
+=item * C<ONLY>
+
+Optional. An array reference containing a list of action names for
+which the paginate parameters should be saved. If missing or empty then
+all actions invoked on the controller are monitored.
+
+=back
+
+=back
+
+=head1 INSTANCE FUNCTIONS
+
+These functions are called on a controller instance.
+
+=over 4
+
+=item C<get_paginate_spec>
+
+Returns a hash containing the currently active paginate
+parameters. The following keys are returned:
+
+=over 4
+
+=item * C<page>
+
+The currently active page number (numbering starts at 1).
+
+=item * C<per_page>
+
+Number of models per page (at least 1).
+
+=item * C<num_pages>
+
+Number of pages to display (at least 1).
+
+=item * C<common_pages>
+
+An array reference with one hash reference for each possible
+page. Each hash ref contains the keys C<active> (C<1> if that page is
+the currently active page), C<page> (the page number this hash
+reference describes) and C<visible> (whether or not it should be
+displayed).
+
+=back
+
+=item C<get_current_paginate_params>
+
+Returns a hash reference to the paginate spec structure given in the call
+to L<make_paginated> after normalization (hash reference construction,
+applying default parameters etc).
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
use Exporter qw(import);
our @EXPORT = qw(make_sorted get_sort_spec get_current_sort_params _save_current_sort_params _get_models_handler_for_sorted _callback_handler_for_sorted);
-my ($controller_sort_spec, $current_sort_by, $current_sort_dir);
+use constant PRIV => '__sortedhelperpriv';
+
+my $controller_sort_spec;
sub make_sorted {
my ($class, %specs) = @_;
$spec->{model_column} ||= $column;
}
- $specs{DEFAULT_DIR} = $specs{DEFAULT_DIR} || !defined($specs{DEFAULT_DIR}) ? 1 : 0;
- $specs{DEFAULT_BY} ||= { "SL::DB::Manager::$specs{MODEL}"->_sort_spec }->{default}->[0];
+ my %model_sort_spec = "SL::DB::Manager::$specs{MODEL}"->_sort_spec;
+ $specs{DEFAULT_DIR} = $specs{DEFAULT_DIR} ? 1 : defined($specs{DEFAULT_DIR}) ? $specs{DEFAULT_DIR} * 1 : $model_sort_spec{default}->[1];
+ $specs{DEFAULT_BY} ||= $model_sort_spec{default}->[0];
$specs{FORM_PARAMS} ||= [ qw(sort_by sort_dir) ];
$specs{ONLY} ||= [];
$specs{ONLY} = [ $specs{ONLY} ] if !ref $specs{ONLY};
my $sort_spec = $self->get_sort_spec;
if (!$params{sort_by}) {
- $params{sort_by} = $current_sort_by;
- $params{sort_dir} = $current_sort_dir;
+ my $priv = $self->{PRIV()} || {};
+ $params{sort_by} = $priv->{by};
+ $params{sort_dir} = $priv->{dir};
}
my $by = $params{sort_by} || $sort_spec->{DEFAULT_BY};
#
sub _save_current_sort_params {
- my ($self) = @_;
+ my ($self) = @_;
- my $sort_spec = $self->get_sort_spec;
- $current_sort_by = $::form->{ $sort_spec->{FORM_PARAMS}->[0] };
- $current_sort_dir = !!$::form->{ $sort_spec->{FORM_PARAMS}->[1] } * 1;
+ my $sort_spec = $self->get_sort_spec;
+ $self->{PRIV()} = {
+ by => $::form->{ $sort_spec->{FORM_PARAMS}->[0] },
+ dir => !!$::form->{ $sort_spec->{FORM_PARAMS}->[1] } * 1,
+ };
- # $::lxdebug->message(0, "saving current sort params to $current_sort_by / $current_sort_dir");
+ # $::lxdebug->message(0, "saving current sort params to " . $self->{PRIV()}->{by} . ' / ' . $self->{PRIV()}->{dir});
}
sub _callback_handler_for_sorted {
my ($self, %params) = @_;
- if ($current_sort_by) {
+ my $priv = $self->{PRIV()} || {};
+ if ($priv->{by}) {
my $sort_spec = $self->get_sort_spec;
- $params{ $sort_spec->{FORM_PARAMS}->[0] } = $current_sort_by;
- $params{ $sort_spec->{FORM_PARAMS}->[1] } = $current_sort_dir;
+ $params{ $sort_spec->{FORM_PARAMS}->[0] } = $priv->{by};
+ $params{ $sort_spec->{FORM_PARAMS}->[1] } = $priv->{dir};
}
# $::lxdebug->dump(0, "CB handler for sorted; params nach modif:", \%params);
sub action_list {
my ($self) = @_;
- my $sorted_models = $self->get_sorted;
+ my $sorted_models = $self->get_models;
$self->render('controller/list', ENTRIES => $sorted_models);
}
A template on the other hand can use the method
C<sortable_table_header> from the layout helper module C<L>.
+This module requires that the Rose model managers use their C<Sorted>
+helper.
+
The C<Sorted> helper hooks into the controller call to the action via
a C<run_before> hook. This is done so that it can remember the sort
parameters that were used in the current view.
second kind are also the indexes you use in a template when calling
C<[% L.sorted_table_header(...) %]>.
-Control parameters include the following (all required parameters
-occur first):
+Control parameters include the following:
=over 4
+=item * C<MODEL>
+
+Optional. A string: the name of the Rose database model that is used
+as a default in certain cases. If this parameter is missing then it is
+derived from the controller's package (e.g. for the controller
+C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
+C<BackgroundJobHistory>).
+
=item * C<DEFAULT_BY>
-Required. A string: the index to sort by if the user hasn't clicked on
+Optional. A string: the index to sort by if the user hasn't clicked on
any column yet (meaning: if the C<$::form> parameters for sorting do
not contain a valid index).
+Defaults to the underlying database model's default sort column name.
+
=item * C<DEFAULT_DIR>
Optional. Default sort direction (ascending for trueish values,
descrending for falsish values).
-Defaults to C<1> if missing.
-
-=item * C<MODEL>
-
-Optional. A string: the name of the Rose database model that is used
-as a default in certain cases. If this parameter is missing then it is
-derived from the controller's package (e.g. for the controller
-C<SL::Controller::BackgroundJobHistory> the C<MODEL> would default to
-C<BackgroundJobHistory>).
+Defaults to the underlying database model's default sort direction.
=item * C<FORM_PARAMS>
use List::MoreUtils qw(any);
sub paginate {
- my ($self, %params) = @_;
- my $page = $params{page} || 1;
- my %args = %{ $params{args} || {} };
-
- my $ret = { };
-
- $ret->{per_page} = per_page($self, %params);
- $ret->{max} = ceil($self->get_all_count(%args), $ret->{per_page}) || 1;
- $ret->{cur} = $page < 1 ? 1
- : $page > $ret->{max} ? $ret->{max}
- : $page;
- $ret->{common} = make_common_pages($ret->{cur}, $ret->{max});
+ my ($self, %params) = @_;
+ my $page = $params{page} || 1;
+ my %args = %{ $params{args} || {} };
+
+ my $ret = { };
+
+ $ret->{per_page} = per_page($self, %params);
+ $ret->{max} = ceil($self->get_all_count(%args), $ret->{per_page}) || 1;
+ $ret->{cur} = $page < 1 ? 1
+ : $page > $ret->{max} ? $ret->{max}
+ : $page;
+ $ret->{common} = make_common_pages($ret->{cur}, $ret->{max});
$params{args}{page} = $ret->{cur};
$params{args}{per_page} = $ret->{per_page};
use SL::DB::Helper::Manager;
use base qw(SL::DB::Helper::Manager);
+use SL::DB::Helper::Paginated;
use SL::DB::Helper::Sorted;
sub object_class { 'SL::DB::BackgroundJob' }
use SL::DB::Helper::Manager;
use base qw(SL::DB::Helper::Manager);
+use SL::DB::Helper::Paginated;
use SL::DB::Helper::Sorted;
sub object_class { 'SL::DB::BackgroundJobHistory' }
--- /dev/null
+package SL::DB::Manager::OrderItem;
+
+use strict;
+
+use SL::DB::Helper::Manager;
+use base qw(SL::DB::Helper::Manager);
+
+use SL::DB::Helper::Paginated;
+use SL::DB::Helper::Sorted;
+
+sub object_class { 'SL::DB::OrderItem' }
+
+__PACKAGE__->make_manager_methods;
+
+sub _sort_spec {
+ return ( columns => { delivery_date => [ 'deliverydate', ],
+ description => [ 'lower(orderitems.description)', ],
+ partnumber => [ 'part.partnumber', ],
+ qty => [ 'qty' ],
+ ordnumber => [ 'order.ordnumber' ],
+ customer => [ 'lower(customer.name)', ],
+ 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 => { }
+ );
+}
+
+sub default_objects_per_page { 40 }
+
+1;
use SL::AM;
use SL::DB::MetaSetup::OrderItem;
+use SL::DB::Manager::OrderItem;
use SL::DB::Helper::CustomVariables (
sub_module => 'orderitems',
cvars_alias => 1,
},
);
-# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
-__PACKAGE__->meta->make_manager_class;
-
__PACKAGE__->meta->initialize;
sub is_price_update_available {
return sum(map { AM->convert_unit($_->unit => $self->unit) * $_->qty } @doi);
}
-package SL::DB::Manager::OrderItem;
-
-use SL::DB::Helper::Paginated;
-use SL::DB::Helper::Sorted;
-
-sub _sort_spec {
- return ( columns => { delivery_date => [ 'deliverydate', ],
- description => [ 'lower(orderitems.description)', ],
- partnumber => [ 'part.partnumber', ],
- qty => [ 'qty' ],
- ordnumber => [ 'order.ordnumber' ],
- customer => [ 'lower(customer.name)', ],
- 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 => { }
- );
-}
-
-sub default_objects_per_page { 40 }
-
1;
return "<${tag}${attributes}>${content}</${tag}>";
}
+sub img_tag {
+ my ($self, @slurp) = @_;
+ my %options = _hashify(@slurp);
+
+ $options{alt} ||= '';
+
+ return $self->html_tag('img', undef, %options);
+}
+
sub select_tag {
my $self = shift;
my $name = shift;
return '<a href="' . $controller->get_callback(%params) . '">' . _H($title) . $image . '</a>';
}
+sub paginate_controls {
+ my ($self) = @_;
+
+ my $controller = $self->{CONTEXT}->stash->get('SELF');
+ my $paginate_spec = $controller->get_paginate_spec;
+ my %paginate_params = $controller->get_current_paginate_params;
+
+ my %template_params = (
+ pages => {
+ cur => $paginate_params{page},
+ max => $paginate_params{num_pages},
+ common => $paginate_params{common_pages},
+ },
+ url_maker => sub {
+ my %url_params = _hashify(@_);
+ $url_params{ $paginate_spec->{FORM_PARAMS}->[0] } = delete $url_params{page};
+ $url_params{ $paginate_spec->{FORM_PARAMS}->[1] } = delete $url_params{per_page} if exists $url_params{per_page};
+
+ return $controller->get_callback(%url_params);
+ },
+ );
+
+ my $output;
+ $controller->_template_obj->process('templates/webpages/common/paginate.html', \%template_params, \$output);
+ return $output;
+}
+
1;
__END__
See the documentation of L<SL::Controller::Helper::Sorted> for an
overview and further usage instructions.
+=item C<paginate_controls>
+
+Create a set of links used to paginate a list view.
+
+See the documentation of L<SL::Controller::Helper::Paginated> for an
+overview and further usage instructions.
+
=back
=head2 CONVERSION FUNCTIONS
# adjust prices by unit, ignore if pricegroup changed
if ((!$form->{"prices_$i"}) || ($form->{"new_pricegroup_$i"} == $form->{"old_pricegroup_$i"})) {
$form->{"sellprice_$i"} *= AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units) || 1;
+ $form->{"lastcost_$i"} *= AM->convert_unit($form->{"selected_unit_$i"}, $form->{"unit_old_$i"}, $all_units) || 1;
$form->{"unit_old_$i"} = $form->{"selected_unit_$i"};
}
my $this_unit = $form->{"unit_$i"};
$column_data{"unit"} = AM->unit_select_html($all_units, "unit_$i", $this_unit, $form->{"id_$i"} ? $form->{"unit_$i"} : undef);
# / unit ending
+#count the max of decimalplaces of sellprice and lastcost, so the same number of decimalplaces
+#is shown for lastcost and sellprice.
my $decimalplaces = ($form->{"sellprice_$i"} =~ /\.(\d+)/) ? max 2, length $1 : 2;
+ $decimalplaces = ($form->{"lastcost_$i"} =~ /\.(\d+)/) ? max $decimalplaces, length $1 : $decimalplaces;
my $price_factor = $price_factors{$form->{"price_factor_id_$i"}} || 1;
my $discount = $form->round_amount($form->{"qty_$i"} * $form->{"sellprice_$i"} * $form->{"discount_$i"} / 100 / $price_factor, 2);
} else {
$real_sellprice = $linetotal;
};
- my $real_lastcost = $form->{"lastcost_$i"} * $form->{"qty_$i"} / ( $form->{"marge_price_factor_$i"} || 1 );
+ my $real_lastcost = $form->round_amount($form->{"lastcost_$i"} * $form->{"qty_$i"} / $price_factor, 2);
my $marge_percent_warn = $myconfig{marge_percent_warn} * 1 || 15;
my $marge_adjust_credit_note = $form->{type} eq 'credit_note' ? -1 : 1;
<b>%s</b> <input size="5" name="lastcost_$i" value="%s">|,
$marge_color, $locale->text('Ertrag'),$form->{"marge_absolut_$i"}, $form->{"marge_percent_$i"},
$locale->text('LP'), $form->format_amount(\%myconfig, $form->{"listprice_$i"}, 2),
- $locale->text('EK'), $form->format_amount(\%myconfig, $form->{"lastcost_$i"}, 2) }
+ $locale->text('EK'), $form->format_amount(\%myconfig, $form->{"lastcost_$i"}, $decimalplaces) }
if $form->{"id_$i"} && ($form->{type} =~ /^sales_/ || $form->{type} =~ /invoice/ || $form->{type} =~ /^credit_note$/ ) && !$is_delivery_order;
$form->{"listprice_$i"} = $form->format_amount(\%myconfig, $form->{"listprice_$i"}, 2)
$ar->{price_factor} = 1 unless $ar->{price_factor};
# calculate individual sellprice
# discount was already accounted for in db sellprice
- $ar->{sellprice} = $ar->{sellprice} / $ar->{price_factor} / $basefactor;
- $ar->{lastcost} = $ar->{lastcost} / $ar->{price_factor};
+ $ar->{sellprice} = $ar->{sellprice} / $ar->{price_factor} / $basefactor;
+ $ar->{lastcost} = $ar->{lastcost} / $ar->{price_factor} / $basefactor;
$ar->{sellprice_total} = $ar->{qty} * ( $ar->{fxsellprice} * ( 1 - $ar->{discount} ) ) / $ar->{price_factor};
$ar->{lastcost_total} = $ar->{qty} * $ar->{lastcost} * $basefactor;
# marge_percent wird neu berechnet, da Wert in invoice leer ist (Bug)
[% USE HTML %][% USE L %][% USE LxERP %]
<body>
- <form method="post" action="controller.pl">
- <div class="listtop">[% FORM.title %]</div>
+ <h1>[% FORM.title %]</h1>
[%- INCLUDE 'common/flash.html' %]
+ <form method="post" action="controller.pl">
<table>
<tr>
<th align="right">[%- LxERP.t8('Active') %]</th>
<p>
[% L.hidden_tag("id", SELF.background_job.id) %]
+ [% L.hidden_tag("back_to", SELF.back_to) %]
[% L.hidden_tag("action", "BackgroundJob/dispatch") %]
[% L.submit_tag("action_" _ (SELF.background_job.id ? "update" : "create"), LxERP.t8('Save')) %]
[%- IF SELF.background_job.id %]
[% USE HTML %][% USE L %][% USE LxERP %]
<body>
- <div class="listtop">[% FORM.title %]</div>
+ <h1>[% FORM.title %]</h1>
[%- INCLUDE 'common/flash.html' %]
<table id="background_job_list" width="100%">
<thead>
<tr class="listheading">
- <th>[%- LxERP.t8('Package name') %]</th>
- <th>[%- LxERP.t8('Execution type') %]</th>
- <th>[%- LxERP.t8('Active') %]</th>
- <th>[%- LxERP.t8('Execution schedule') %]</th>
- <th>[%- LxERP.t8('Last run at') %]</th>
- <th>[%- LxERP.t8('Next run at') %]</th>
+ <th>[% L.sortable_table_header('package_name') %]</th>
+ <th>[% L.sortable_table_header('type') %]</th>
+ <th>[% L.sortable_table_header('active') %]</th>
+ <th>[% L.sortable_table_header('cron_spec') %]</th>
+ <th>[% L.sortable_table_header('last_run_at') %]</th>
+ <th>[% L.sortable_table_header('next_run_at') %]</th>
</tr>
</thead>
[%- FOREACH background_job = BACKGROUND_JOBS %]
<tr class="listrow[% loop.count % 2 %]" id="background_job_id_[% background_job.id %]">
<td>
- <a href="[% SELF.url_for(action => 'edit', id => background_job.id) %]">
+ <a href="[% SELF.url_for(action => 'edit', id => background_job.id, back_to => SELF.get_callback) %]">
[%- HTML.escape(background_job.package_name) %]
</a>
</td>
</table>
[%- END %]
+ [% L.paginate_controls %]
+
<hr size="3" noshade>
<p>
- <a href="[% SELF.url_for(action => 'new') %]">[%- LxERP.t8('Create new background job') %]</a>
+ <a href="[% SELF.url_for(action => 'new', back_to => SELF.get_callback) %]">[%- LxERP.t8('Create new background job') %]</a>
|
<a href="[% SELF.url_for(controller => 'BackgroundJobHistory', action => 'list') %]">[%- LxERP.t8('View background job history') %]</a>
|
[% USE HTML %][% USE L %][% USE LxERP %]
<body>
- <div class="listtop">[% FORM.title %]</div>
+ <h1>[% FORM.title %]</h1>
[%- INCLUDE 'common/flash.html' %]
</table>
[%- END %]
+ [% L.paginate_controls %]
+
<hr size="3" noshade>
<p>
[% USE HTML %][% USE L %][% USE LxERP %]
<body>
- <div class="listtop">[% FORM.title %]</div>
+ <h1>[% FORM.title %]</h1>
[%- INCLUDE 'common/flash.html' %]
[%- USE T8 %]
-<span class='paginate'>
+[%- MACRO build_url BLOCK %]
+ [%- IF base_url %]
+ [%- base_url %]&page=[% page %]
+ [%- ELSE %]
+ [% url_maker('page' => page) %]
+ [%- END %]
+[%- END %]
[%- IF pages.max > 1 %]
-[%- IF pages.cur > 1 %]<a class='paginate-prev' href='[% base_url _ "&page=" _ (pages.cur - 1) %]'>« [% 'prev' | $T8 %]</a> [% ELSE %]<b>«</b> [% END %]
+<div class='paginate'>
+[%- IF pages.cur > 1 %]<a class='paginate-prev' href='[% build_url(page=pages.cur - 1) %]'>« [% 'prev' | $T8 %]</a> [% ELSE %]<b>«</b> [% END %]
[%- FOR p = pages.common %]
[%- NEXT UNLESS p.visible %]
- [%- IF p.active %]<a class='paginate-page' href="[% base_url _ "&page=" _ p.page %]">[% p.page %]</a> [% ELSE %]<b>[% p.page %]</b> [%- END %]
+ [%- IF p.active %]<a class='paginate-page' href="[% build_url(page=p.page) %]">[% p.page %]</a> [% ELSE %]<b>[% p.page %]</b> [%- END %]
[%- END %]
-[%- IF pages.cur < pages.max %]<a class='paginate-next' href='[% base_url _ "&page=" _ (pages.cur + 1) %]'>[% 'next' | $T8 %] »</a>[% ELSE %]<b>»</b>[%- END %]
+[%- IF pages.cur < pages.max %]<a class='paginate-next' href='[% build_url(page=pages.cur + 1) %]'>[% 'next' | $T8 %] »</a>[% ELSE %]<b>»</b>[%- END %]
+</div>
[%- END %]
</tr>
[%- END %]
</table>
- <p align=right>[% PROCESS 'common/paginate.html' pages=SELF.pages, base_url=SELF.url_for(action='list', sort_dir=SELF.sort_dir, sort_by=SELF.sort_by) %]</p>
+ [% PROCESS 'common/paginate.html' pages=SELF.pages, base_url=SELF.url_for(action='list', sort_dir=SELF.sort_dir, sort_by=SELF.sort_by) %]
[%- END %]
</div>
[% SET report_bottom_url_args = {} %]
[% report_bottom_url_args.import(SELF.flat_filter) %]
[% report_bottom_url_args.import({action='list', sort_dir=SELF.sort_dir, sort_by=SELF.sort_by}) %]
-<p align=right>[% PROCESS 'common/paginate.html' pages=SELF.pages, base_url=SELF.url_for(report_bottom_url_args) %]</p>
+[% PROCESS 'common/paginate.html' pages=SELF.pages, base_url=SELF.url_for(report_bottom_url_args) %]