LEFT JOIN tax tx ON (tk.tax_id = tx.id)
WHERE 1=1
$where
- GROUP BY c.accno, c.id, c.description, c.charttype, c.gifi_accno,
+ GROUP BY c.accno, c.id, c.description, c.charttype,
c.category, c.link, c.pos_bwa, c.pos_bilanz, c.pos_eur, c.valid_from,
c.datevautomatik
ORDER BY c.accno
--- /dev/null
+package SL::ClientJS;
+
+use strict;
+
+use parent qw(Rose::Object);
+
+use Carp;
+use SL::JSON ();
+
+use Rose::Object::MakeMethods::Generic
+(
+ 'scalar --get_set_init' => [ qw(_actions) ],
+);
+
+my %supported_methods = (
+ # Basic effects
+ hide => 1,
+ show => 1,
+ toggle => 1,
+
+ # DOM insertion, around
+ unwrap => 1,
+ wrap => 2,
+ wrapAll => 2,
+ wrapInner => 2,
+
+ # DOM insertion, inside
+ append => 2,
+ appendTo => 2,
+ html => 2,
+ prepend => 2,
+ prependTo => 2,
+ text => 2,
+
+ # DOM insertion, outside
+ after => 2,
+ before => 2,
+ insertAfter => 2,
+ insertBefore => 2,
+
+ # DOM removal
+ empty => 1,
+ remove => 1,
+
+ # DOM replacement
+ replaceAll => 2,
+ replaceWith => 2,
+
+ # General attributes
+ attr => 3,
+ prop => 3,
+ removeAttr => 2,
+ removeProp => 2,
+ val => 2,
+
+ # Data storage
+ data => 3,
+ removeData => 2,
+);
+
+sub AUTOLOAD {
+ our $AUTOLOAD;
+
+ my ($self, @args) = @_;
+
+ my $method = $AUTOLOAD;
+ $method =~ s/.*:://;
+ return if $method eq 'DESTROY';
+
+ my $num_args = $supported_methods{$method};
+ $::lxdebug->message(0, "autoload method $method");
+
+ croak "Unsupported jQuery action: $method" unless defined $num_args;
+ croak "Parameter count mismatch for $method(actual: " . scalar(@args) . " wanted: $num_args)" if scalar(@args) != $num_args;
+
+ if ($num_args) {
+ # Force flattening from SL::Presenter::EscapedText: "" . $...
+ $args[0] = "" . $args[0];
+ $args[0] =~ s/^\s+//;
+ }
+
+ push @{ $self->_actions }, [ $method, @args ];
+
+ return $self;
+}
+
+sub init__actions {
+ return [];
+}
+
+sub to_json {
+ my ($self) = @_;
+ return SL::JSON::to_json({ eval_actions => $self->_actions });
+}
+
+sub to_array {
+ my ($self) = @_;
+ return $self->_actions;
+}
+
+1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::ClientJS - Easy programmatic client-side JavaScript generation
+with jQuery
+
+=head1 SYNOPSIS
+
+First some JavaScript code:
+
+ // In the client generate an AJAX request whose 'success' handler
+ // calls "eval_json_response(data)":
+ var data = {
+ action: "SomeController/the_action",
+ id: $('#some_input_field').val()
+ };
+ $.post("controller.pl", data, eval_json_response);
+
+Now some Perl code:
+
+ # In the controller itself. First, make sure that the "client_js.js"
+ # is loaded. This must be done when the whole side is loaded, so
+ # it's not in the action called by the AJAX request shown above.
+ $::request->layout->use_javascript('client_js.js');
+
+ # Now in that action called via AJAX:
+ sub action_the_action {
+ my ($self) = @_;
+
+ # Create a new client-side JS object and do stuff with it!
+ my $js = SL::ClientJS->new;
+
+ # Show some element on the page:
+ $js->show('#usually_hidden');
+
+ # Set to hidden inputs. Yes, calls can be chained!
+ $js->val('#hidden_id', $self->new_id)
+ ->val('#other_type', 'Unicorn');
+
+ # Replace some HTML code:
+ my $html = $self->render('SomeController/the_action', { output => 0 });
+ $js->html('#id_with_new_content', $html);
+
+ # Finally render the JSON response:
+ $self->render($js);
+ }
+
+=head1 OVERVIEW
+
+This module enables the generation of jQuery-using JavaScript code on
+the server side. That code is then evaluated in a safe way on the
+client side.
+
+The workflow is usally that the client creates an AJAX request, the
+server creates some actions and sends them back, and the client then
+implements each of these actions.
+
+There are three things that need to be done for this to work:
+
+=over 2
+
+=item 1. The "client_js.js" has to be loaded before the AJAX request is started.
+
+=item 2. The client code needs to call C<eval_json_response()> with the result returned from the server.
+
+=item 3. The server must use this module.
+
+=back
+
+The functions called on the client side are mostly jQuery
+functions. Other functionality may be added later.
+
+Note that L<SL::Controller/render> is aware of this module which saves
+you some boilerplate. The following two calls are equivalent:
+
+ $controller->render($client_js);
+ $controller->render(\$client_js->to_json, { type => 'json' });
+
+=head1 FUNCTIONS NOT PASSED TO THE CLIENT SIDE
+
+=over 4
+
+=item C<to_array>
+
+Returns the actions gathered so far as an array reference. Each
+element is an array reference containing at least two items: the
+function's name and what it is called on. Additional array elements
+are the function parameters.
+
+=item C<to_json>
+
+Returns the actions gathered so far as a JSON string ready to be sent
+to the client.
+
+=back
+
+=head1 FUNCTIONS EVALUATED ON THE CLIENT SIDE
+
+=head2 JQUERY FUNCTIONS
+
+The following jQuery functions are supported:
+
+=over 4
+
+=item Basic effects
+
+C<hide>, C<show>, C<toggle>
+
+=item DOM insertion, around
+
+C<unwrap>, C<wrap>, C<wrapAll>, C<wrapInner>
+
+=item DOM insertion, inside
+
+C<append>, C<appendTo>, C<html>, C<prepend>, C<prependTo>, C<text>
+
+=item DOM insertion, outside
+
+C<after>, C<before>, C<insertAfter>, C<insertBefore>
+
+=item DOM removal
+
+C<empty>, C<remove>
+
+=item DOM replacement
+
+C<replaceAll>, C<replaceWith>
+
+=item General attributes
+
+C<attr>, C<prop>, C<removeAttr>, C<removeProp>, C<val>
+
+=item Data storage
+
+C<data>, C<removeData>
+
+=back
+
+=head1 ADDING SUPPORT FOR ADDITIONAL FUNCTIONS
+
+In order not having to maintain two files (this one and
+C<js/client_js.js>) there's a script that can parse this file's
+C<%supported_methods> definition and convert it into the appropriate
+code ready for manual insertion into C<js/client_js.js>. The steps
+are:
+
+=over 2
+
+=item 1. Add lines in this file to the C<%supported_methods> hash. The
+key is the function name and the value is the number of expected
+parameters.
+
+=item 2. Run C<scripts/generate_client_js_actions.pl>
+
+=item 3. Edit C<js/client_js.js> and replace the type casing code with
+the output generated in step 2.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
my $template = shift;
my ($options, %locals) = (@_ && ref($_[0])) ? @_ : ({ }, @_);
+ # Special handling/shortcut for an instance of SL::ClientJS:
+ return $self->render(\$template->to_json, { type => 'json' }) if ref($template) eq 'SL::ClientJS';
+
# Set defaults for all available options.
my %defaults = (
type => 'html',
use strict;
use parent qw(Exporter);
-our @EXPORT = qw(move_position_up move_position_down add_to_list remove_from_list reorder_list configure_acts_as_list);
+our @EXPORT = qw(move_position_up move_position_down add_to_list remove_from_list reorder_list configure_acts_as_list
+ get_previous_in_list get_next_in_list);
use Carp;
return $self->db->in_transaction ? $worker->() : $self->db->do_transaction($worker);
}
+sub get_next_in_list {
+ my ($self) = @_;
+ return get_previous_or_next($self, 'next');
+}
+
+sub get_previous_in_list {
+ my ($self) = @_;
+ return get_previous_or_next($self, 'previous');
+}
+
sub reorder_list {
my ($class_or_self, @ids) = @_;
$self->update_attributes($column => $new_position);
}
+sub get_previous_or_next {
+ my ($self, $direction) = @_;
+
+ my $asc_desc = $direction eq 'next' ? 'ASC' : 'DESC';
+ my $comparator = $direction eq 'next' ? '>' : '<';
+ my $table = $self->meta->table;
+ my $column = column_name($self);
+ my $primary_key_col = ($self->meta->primary_key)[0];
+ my ($group_by, @values) = get_group_by_where($self);
+ $group_by = " AND ${group_by}" if $group_by;
+ my $sql = <<SQL;
+ SELECT ${primary_key_col}
+ FROM ${table}
+ WHERE (${column} ${comparator} ?)
+ ${group_by}
+ ORDER BY ${column} ${asc_desc}
+ LIMIT 1
+SQL
+
+ my $id = ($self->db->dbh->selectrow_arrayref($sql, undef, $self->$column, @values) || [])->[0];
+
+ return $id ? $self->_get_manager_class->find_by(id => $id) : undef;
+}
+
sub column_name {
my ($self) = @_;
my $column = get_spec(ref $self, 'column_name');
Sets this items positional column to C<-1>, saves it and moves all
following items up by 1.
+=item C<get_previous_in_list>
+
+Fetches the previous item in the list. Returns C<undef> if C<$self> is
+already the first one.
+
+=item C<get_next_in_list>
+
+Fetches the next item in the list. Returns C<undef> if C<$self> is
+already the last one.
+
=item C<reorder_list @ids>
Re-orders the objects given in C<@ids> by their position in C<@ids> by
$trq->finish;
# is it an orphan
- my @referencing_tables = qw(invoice orderitems inventory rmaitems);
+ my @referencing_tables = qw(invoice orderitems inventory);
my %column_map = ( );
my $parts_id = conv_i($form->{id});
$dumper->Sortkeys(1);
$dumper->Indent(2);
$dumper->$_($options{$_}) for keys %options;
- $self->message($level, "dumping ${name}:\n" . $dumper->Dump());
+ my $output = $dumper->Dump();
+ $self->message($level, "dumping ${name}:\n" . $output);
$variable->{password} = $password if (defined $password);
keys %{ $variable };
}
+ return $output;
+
} else {
$self->message($level,
"dumping ${name}: Data::Dumper not available; "
. "variable cannot be dumped");
+
+ return undef;
}
}
sub javascripts {
my ($self) = @_;
- return uniq map { $self->_find_javascript($_) }
+ return uniq grep { $_ } map { $self->_find_javascript($_) }
map({ $_->javascripts } $self->sub_layouts), $self->use_javascript;
}
use List::MoreUtils qw(apply);
sub javascripts_inline {
- _setup_formats(),
- _setup_focus(),
+ my ($self) = @_;
+
+ my $datefmt = apply {
+ s/d+/dd/gi;
+ s/m+/mm/gi;
+ s/y+/yy/gi;
+ } $::myconfig{dateformat};
+
+ return $self->render(
+ 'layout/javascript_setup',
+ { type => 'js', output => 0, },
+ datefmt => $datefmt,
+ focus => $::request->layout->focus,
+ ajax_spinner => 1,
+ );
}
sub use_javascript {
$self->SUPER::use_stylesheet(@_);
}
-sub _setup_formats {
- my $datefmt = apply {
- s/d+/dd/gi;
- s/m+/mm/gi;
- s/y+/yy/gi;
- } $::myconfig{dateformat};
-
- $::form->parse_html_template('layout/javascript_setup', { datefmt => $datefmt });
-}
-
-sub _setup_focus {
- if ($::request->{layout}->focus) {
- return $::form->parse_html_template('layout/focus_setup', {
- focus => $::request->{layout}->focus,
- })
- } else {
- return ();
- }
-}
-
1;
my $first = 1;
$where .= qq| AND id NOT IN (|;
- foreach my $table (qw(invoice orderitems prices rmaitems)) {
+ foreach my $table (qw(invoice orderitems prices)) {
$where .= "UNION " unless ($first);
$first = 0;
$where .=
my @values = ();
$query = qq|SELECT |;
- foreach my $table (qw(invoice orderitems prices rmaitems)) {
+ foreach my $table (qw(invoice orderitems prices)) {
$query .= " + " unless ($first);
$first = 0;
$query .= qq|(SELECT COUNT(*) FROM $table WHERE pricegroup_id = ?) |;
return SL::Presenter::EscapedText->new(text => $text, is_escaped => 1);
}
+sub escape_js {
+ my ($self, $text) = @_;
+
+ $text =~ s|\\|\\\\|g;
+ $text =~ s|\"|\\\"|g;
+ $text =~ s|\n|\\n|g;
+
+ return SL::Presenter::EscapedText->new(text => $text, is_escaped => 1);
+}
+
1;
__END__
L<SL::Presenter::EscapedText>. This is a no-op (the same instance will
be returned).
+=item C<escape_js $text>
+
+Returns a JavaScript-escaped version of C<$text>. Instead of a string
+an instance of the thin proxy-object L<SL::Presenter::EscapedText> is
+returned.
+
+It is safe to call C<escape> on an instance of
+L<SL::Presenter::EscapedText>. This is a no-op (the same instance will
+be returned).
+
=item C<get_template>
Returns the global instance of L<Template> and creates it if it
my $query;
my $dpt_where = '';
- my $dpt_join = '';
+ my $dpt_where_without_arapgl = '';
my $project = '';
my $where = "1 = 1";
my $glwhere = "";
}
if ($department_id) {
- $dpt_join = qq| JOIN department t ON (a.department_id = t.id) |;
- $dpt_where = qq| AND (t.id = | . conv_i($department_id, 'NULL') . qq|)|;
+ $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|)|;
}
if ($form->{project_id}) {
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
JOIN ar a ON (a.id = ac.trans_id)
- $dpt_join
WHERE $where
$dpt_where
$category
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
JOIN ap a ON (a.id = ac.trans_id)
- $dpt_join
WHERE $where
$dpt_where
$category
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
JOIN gl a ON (a.id = ac.trans_id)
- $dpt_join
WHERE $where
$glwhere
$dpt_where
JOIN ar a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.income_accno_id = c.id)
- $dpt_join
-- use transdate from subwhere
WHERE (c.category = 'I')
$subwhere
JOIN ap a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.expense_accno_id = c.id)
- $dpt_join
WHERE (c.category = 'E')
$subwhere
$dpt_where
} else { # if ($form->{method} eq 'cash')
if ($department_id) {
- $dpt_join = qq| JOIN dpt_trans t ON (t.trans_id = ac.trans_id) |;
- $dpt_where = qq| AND t.department_id = | . conv_i($department_id);
+ $dpt_where = qq| AND a.department_id = | . conv_i($department_id);
+ $dpt_where_without_arapgl = qq| AND COALESCE((SELECT department_id FROM ar WHERE ar.id=ac.trans_id),
+ (SELECT department_id FROM gl WHERE gl.id=ac.trans_id),
+ (SELECT department_id FROM ap WHERE ap.id=ac.trans_id)) = | . conv_i($department_id);
}
$query = qq|
SELECT c.accno, sum(ac.amount) AS amount, c.description, c.category
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
- $dpt_join
WHERE $where
- $dpt_where
+ $dpt_where_without_arapgl
$category
$project
GROUP BY c.accno, c.description, c.category |;
JOIN ar a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.income_accno_id = c.id)
- $dpt_join
-- use transdate from subwhere
WHERE (c.category = 'I')
$subwhere
JOIN ap a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.expense_accno_id = c.id)
- $dpt_join
WHERE (c.category = 'E')
$subwhere
$dpt_where
my $query;
my $dpt_where;
- my $dpt_join;
+ my $dpt_where_without_arapgl;
my $project;
my $where = "1 = 1";
my $glwhere = "";
}
if ($department_id) {
- $dpt_join = qq| JOIN department t ON (a.department_id = t.id) |;
- $dpt_where = qq| AND (t.id = | . conv_i($department_id, 'NULL') . qq|) |;
+ $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
}
if ($form->{project_id}) {
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
JOIN ar a ON (a.id = ac.trans_id)
- $dpt_join
WHERE $where $dpt_where
AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a JOIN chart c ON (a.chart_id = c.id) WHERE (link LIKE '%AR_paid%') $subwhere)
$project
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
JOIN ap a ON (a.id = ac.trans_id)
- $dpt_join
WHERE $where $dpt_where
AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a JOIN chart c ON (a.chart_id = c.id) WHERE (link LIKE '%AP_paid%') $subwhere)
$project
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
JOIN gl a ON (a.id = ac.trans_id)
- $dpt_join
WHERE $where $dpt_where $glwhere
AND NOT ((c.link = 'AR') OR (c.link = 'AP'))
$project
JOIN ar a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.income_accno_id = c.id)
- $dpt_join
WHERE (c.category = 'I') $prwhere $dpt_where
AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a JOIN chart c ON (a.chart_id = c.id) WHERE (link LIKE '%AR_paid%') $subwhere)
$project
JOIN ap a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.expense_accno_id = c.id)
- $dpt_join
WHERE (c.category = 'E') $prwhere $dpt_where
AND ac.trans_id IN ( SELECT trans_id FROM acc_trans a JOIN chart c ON (a.chart_id = c.id) WHERE (link LIKE '%AP_paid%') $subwhere)
$project
} else { # if ($form->{method} eq 'cash')
if ($department_id) {
- $dpt_join = qq| JOIN dpt_trans t ON (t.trans_id = ac.trans_id) |;
- $dpt_where = qq| AND (t.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
+ $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
+ $dpt_where_without_arapgl = qq| AND COALESCE((SELECT department_id FROM ar WHERE ar.id=ac.trans_id),
+ (SELECT department_id FROM gl WHERE gl.id=ac.trans_id),
+ (SELECT department_id FROM ap WHERE ap.id=ac.trans_id)) = | . conv_i($department_id);
}
$query = qq|
SELECT sum(ac.amount * chart_category_to_sgn(c.category)) AS amount, c.$category
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
- $dpt_join
WHERE $where
- $dpt_where
+ $dpt_where_without_arapgl
$project
GROUP BY c.$category |;
JOIN ar a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.income_accno_id = c.id)
- $dpt_join
WHERE (c.category = 'I')
$prwhere
$dpt_where
JOIN ap a ON (a.id = ac.trans_id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c on (p.expense_accno_id = c.id)
- $dpt_join
WHERE (c.category = 'E')
$prwhere
$dpt_where
my ($null, $department_id) = split /--/, $form->{department};
my @headingaccounts = ();
my $dpt_where;
- my $dpt_join;
+ my $dpt_where_without_arapgl;
my $project;
my $where = "1 = 1";
my $invwhere = $where;
if ($department_id) {
- $dpt_join = qq| JOIN dpt_trans t ON (ac.trans_id = t.trans_id) |;
- $dpt_where = qq| AND (t.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
+ $dpt_where = qq| AND (a.department_id = | . conv_i($department_id, 'NULL') . qq|) |;
+ $dpt_where_without_arapgl = qq| AND COALESCE((SELECT department_id FROM ar WHERE ar.id=ac.trans_id),
+ (SELECT department_id FROM gl WHERE gl.id=ac.trans_id),
+ (SELECT department_id FROM ap WHERE ap.id=ac.trans_id)) = | . conv_i($department_id);
}
# project_id only applies to getting transactions
my $min_max = $prefix eq 'from' ? 'min' : 'max';
$query = qq|SELECT ${min_max}(transdate)
FROM acc_trans ac
- $dpt_join
WHERE (1 = 1)
- $dpt_where
+ $dpt_where_without_arapgl
$project|;
($form->{"${prefix}date"}) = selectfirst_array_query($form, $dbh, $query);
}
qq|SELECT c.accno, c.category, SUM(ac.amount) AS amount, c.description
FROM acc_trans ac
LEFT JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE ((select date_trunc('year', ac.transdate::date)) = (select date_trunc('year', ?::date))) AND ac.ob_transaction
- $dpt_where
+ $dpt_where_without_arapgl
$project
GROUP BY c.accno, c.category, c.description |;
SELECT c.accno, c.description, c.category, SUM(ac.amount) AS amount
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
- $dpt_join
WHERE $where
- $dpt_where
+ $dpt_where_without_arapgl
$project
GROUP BY c.accno, c.description, c.category |;
JOIN ar a ON (ac.trans_id = a.id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c ON (p.income_accno_id = c.id)
- $dpt_join
WHERE $invwhere
$dpt_where
$project
JOIN ap a ON (ac.trans_id = a.id)
JOIN parts p ON (ac.parts_id = p.id)
JOIN chart c ON (p.expense_accno_id = c.id)
- $dpt_join
WHERE $invwhere
$dpt_where
$project
(SELECT SUM(ac.amount) * -1
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
- $dpt_join
WHERE $where
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND (ac.amount < 0)
AND (c.accno = ?)) AS debit,
(SELECT SUM(ac.amount)
FROM acc_trans ac
JOIN chart c ON (c.id = ac.chart_id)
- $dpt_join
WHERE $where
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND ac.amount > 0
AND c.accno = ?) AS credit,
(SELECT SUM(ac.amount)
FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $saldowhere
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND c.accno = ? AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL)) AS saldo,
(SELECT SUM(ac.amount)
FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $sumwhere
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND amount > 0
AND c.accno = ?) AS sum_credit,
(SELECT SUM(ac.amount)
FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $sumwhere
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND amount < 0
AND c.accno = ?) AS sum_debit,
(SELECT max(ac.transdate) FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $where
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND c.accno = ?) AS last_transaction
JOIN parts p ON (ac.parts_id = p.id)
JOIN ap a ON (ac.trans_id = a.id)
JOIN chart c ON (p.expense_accno_id = c.id)
- $dpt_join
WHERE $invwhere
$dpt_where
$project
JOIN parts p ON (ac.parts_id = p.id)
JOIN ar a ON (ac.trans_id = a.id)
JOIN chart c ON (p.income_accno_id = c.id)
- $dpt_join
WHERE $invwhere
$dpt_where
$project
(SELECT SUM(ac.amount)
FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $saldowhere
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND c.accno = ? AND (NOT ac.ob_transaction OR ac.ob_transaction IS NULL)) AS saldo,
(SELECT SUM(ac.amount)
FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $sumwhere
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND amount > 0
AND c.accno = ?) AS sum_credit,
(SELECT SUM(ac.amount)
FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $sumwhere
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND amount < 0
AND c.accno = ?) AS sum_debit,
(SELECT max(ac.transdate) FROM acc_trans ac
JOIN chart c ON (ac.chart_id = c.id)
- $dpt_join
WHERE $where
- $dpt_where
+ $dpt_where_without_arapgl
$project
AND c.accno = ?) AS last_transaction
|;
}
my ($query, $sth);
- my $dpt_join;
my $where;
if ($form->{department_id}) {
- $dpt_join = qq| JOIN dpt_trans t ON (t.trans_id = ac.trans_id) |;
- $where = qq| AND (t.department_id = | . conv_i($form->{department_id}, 'NULL') . qq|) |;
+ $where = qq| AND (a.department_id = | . conv_i($form->{department_id}, 'NULL') . qq|) |;
}
if ($form->{fromdate}) {
if ($form->{reference}) {
$reference = $dbh->quote('%' . $form->{reference} . '%');
$invnumber = " AND (a.invnumber LIKE $reference)";
- $reference = " AND (g.reference LIKE $reference)";
+ $reference = " AND (a.reference LIKE $reference)";
}
if ($form->{source}) {
$where .= " AND (ac.source ILIKE " . $dbh->quote('%' . $form->{source} . '%') . ") ";
'memo' => [ qw(lower_memo) ],
);
my %lowered_columns = (
- 'invnumber' => { 'gl' => 'g.reference', 'arap' => 'a.invnumber', },
+ 'invnumber' => { 'gl' => 'a.reference', 'arap' => 'a.invnumber', },
'memo' => { 'gl' => 'ac.memo', 'arap' => 'ac.memo', },
'source' => { 'gl' => 'ac.source', 'arap' => 'ac.source', },
- 'name' => { 'gl' => 'g.description', 'arap' => 'c.name', },
+ 'name' => { 'gl' => 'a.description', 'arap' => 'c.name', },
);
my $sortdir = !defined $form->{sortdir} ? 'ASC' : $form->{sortdir} ? 'ASC' : 'DESC';
FROM acc_trans ac
JOIN $arap a ON (ac.trans_id = a.id)
JOIN $table c ON (c.id = a.${table}_id)
- $dpt_join
WHERE (ac.chart_id = ?)
$where
$invnumber
UNION
- SELECT g.description, g.reference, NULL AS ordnumber,
+ SELECT a.description, a.reference, NULL AS ordnumber,
ac.transdate, ac.amount * $ml AS paid, ac.source,
- '0' as invoice, g.id, ac.memo, 'gl' AS module
+ '0' as invoice, a.id, ac.memo, 'gl' AS module
$columns_for_sorting{gl}
FROM acc_trans ac
- JOIN gl g ON (g.id = ac.trans_id)
- $dpt_join
+ JOIN gl a ON (a.id = ac.trans_id)
WHERE (ac.chart_id = ?)
$where
$reference
$main::lxdebug->leave_sub();
}
-sub ustva {
- $main::lxdebug->enter_sub();
-
- my ($self, $myconfig, $form) = @_;
-
- # connect to database
- my $dbh = $form->dbconnect($myconfig);
-
- my $last_period = 0;
- my @categories_cent = qw(51r 511 86r 861 97r 971 93r 931
- 96 66 43 45 53 62 65 67);
- my @categories_euro = qw(48 51 86 91 97 93 94);
- $form->{decimalplaces} *= 1;
-
- foreach my $item (@categories_cent) {
- $form->{"$item"} = 0;
- }
- foreach my $item (@categories_euro) {
- $form->{"$item"} = 0;
- }
-
- &get_accounts_g($dbh, $last_period, $form->{fromdate}, $form->{todate}, $form, "pos_ustva");
-
- # foreach $item (@categories_cent) {
- # if ($form->{$item}{"jetzt"} > 0) {
- # $form->{$item} = $form->{$item}{"jetzt"};
- # delete $form->{$item}{"jetzt"};
- # }
- # }
- # foreach $item (@categories_euro) {
- # if ($form->{$item}{"jetzt"} > 0) {
- # $form->{$item} = $form->{$item}{"jetzt"};
- # delete $form->{$item}{"jetzt"};
- # } foreach $item (@categories_cent) {
- # if ($form->{$item}{"jetzt"} > 0) {
- # $form->{$item} = $form->{$item}{"jetzt"};
- # delete $form->{$item}{"jetzt"};
- # }
- # }
- # foreach $item (@categories_euro) {
- # if ($form->{$item}{"jetzt"} > 0) {
- # $form->{$item} = $form->{$item}{"jetzt"};
- # delete $form->{$item}{"jetzt"};
- # }
- # }
- #
- # }
-
- #
- # Berechnung der USTVA Formularfelder
- #
- $form->{"51r"} = $form->{"511"};
- $form->{"86r"} = $form->{"861"};
- $form->{"97r"} = $form->{"971"};
- $form->{"93r"} = $form->{"931"};
-
- #$form->{"96"} = $form->{"94"} * 0.16;
- $form->{"43"} =
- $form->{"51r"} + $form->{"86r"} + $form->{"97r"} + $form->{"93r"} +
- $form->{"96"};
- $form->{"45"} = $form->{"43"};
- $form->{"53"} = $form->{"43"};
- $form->{"62"} = $form->{"43"} - $form->{"66"};
- $form->{"65"} = $form->{"43"} - $form->{"66"};
- $form->{"67"} = $form->{"43"} - $form->{"66"};
-
- foreach my $item (@categories_cent) {
- $form->{$item} =
- $form->format_amount($myconfig, $form->round_amount($form->{$item}, 2),
- 2, '0');
- }
-
- foreach my $item (@categories_euro) {
- $form->{$item} =
- $form->format_amount($myconfig, $form->round_amount($form->{$item}, 0),
- 0, '0');
- }
-
- $dbh->disconnect;
-
- $main::lxdebug->leave_sub();
-}
-
sub income_statement {
$main::lxdebug->enter_sub();
# User name to use for database access
login =
# Set to 1 for debug messages in /tmp/kivitendo-debug.log
-debug = 1
+debug = 0
# Chose a system user the daemon should run under when started as root.
run_as =
padding: 0;
border: 0;
overflow: hidden;
+ min-height: 20px;
width: 100%;
border-spacing: 0;
font-size: 12px;
font-family: verdana,arial,sans-serif;
vertical-align: middle;
}
+
+#frame-header #ajax-spinner {
+ margin-top: 2px;
+ margin-right: 10px;
+ display: none;
+}
color: white;
border: 0;
overflow: hidden;
+ min-height: 20px;
width: 100%;
border-spacing: 0;
font-size: 12px;
font-family: verdana,arial,sans-serif;
vertical-align: middle;
}
+
+#frame-header #ajax-spinner {
+ margin-top: 2px;
+ margin-right: 10px;
+ display: none;
+ width: 16px;
+ height: 16px;
+ min-width: 16px;
+ min-height: 16px;
+}
--- /dev/null
+// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE:
+
+// Generate the dispatching lines in this script by running
+// "scripts/generate_client_js_actions.pl". See the documentation for
+// SL/ClientJS.pm for instructions.
+
+function eval_json_result(data) {
+ if (!data)
+ return;
+
+ if ((data.js || '') != '')
+ eval(data.js);
+
+ if (data.eval_actions)
+ $(data.eval_actions).each(function(idx, action) {
+ // console.log("ACTION " + action[0] + " ON " + action[1]);
+
+ // Basic effects
+ if (action[0] == 'hide') $(action[1]).hide();
+ else if (action[0] == 'show') $(action[1]).show();
+ else if (action[0] == 'toggle') $(action[1]).toggle();
+
+ // DOM insertion, around
+ else if (action[0] == 'unwrap') $(action[1]).unwrap();
+ else if (action[0] == 'wrap') $(action[1]).wrap(action[2]);
+ else if (action[0] == 'wrapAll') $(action[1]).wrapAll(action[2]);
+ else if (action[0] == 'wrapInner') $(action[1]).wrapInner(action[2]);
+
+ // DOM insertion, inside
+ else if (action[0] == 'append') $(action[1]).append(action[2]);
+ else if (action[0] == 'appendTo') $(action[1]).appendTo(action[2]);
+ else if (action[0] == 'html') $(action[1]).html(action[2]);
+ else if (action[0] == 'prepend') $(action[1]).prepend(action[2]);
+ else if (action[0] == 'prependTo') $(action[1]).prependTo(action[2]);
+ else if (action[0] == 'text') $(action[1]).text(action[2]);
+
+ // DOM insertion, outside
+ else if (action[0] == 'after') $(action[1]).after(action[2]);
+ else if (action[0] == 'before') $(action[1]).before(action[2]);
+ else if (action[0] == 'insertAfter') $(action[1]).insertAfter(action[2]);
+ else if (action[0] == 'insertBefore') $(action[1]).insertBefore(action[2]);
+
+ // DOM removal
+ else if (action[0] == 'empty') $(action[1]).empty();
+ else if (action[0] == 'remove') $(action[1]).remove();
+
+ // DOM replacement
+ else if (action[0] == 'replaceAll') $(action[1]).replaceAll(action[2]);
+ else if (action[0] == 'replaceWith') $(action[1]).replaceWith(action[2]);
+
+ // General attributes
+ else if (action[0] == 'attr') $(action[1]).attr(action[2], action[3]);
+ else if (action[0] == 'prop') $(action[1]).prop(action[2], action[3]);
+ else if (action[0] == 'removeAttr') $(action[1]).removeAttr(action[2]);
+ else if (action[0] == 'removeProp') $(action[1]).removeProp(action[2]);
+ else if (action[0] == 'val') $(action[1]).val(action[2]);
+
+ // Data storage
+ else if (action[0] == 'data') $(action[1]).data(action[2], action[3]);
+ else if (action[0] == 'removeData') $(action[1]).removeData(action[2]);
+
+ else console.log("Unknown action: " + action[0]);
+ });
+
+ console.log("current_content_type " + $('#current_content_type').val() + ' ID ' + $('#current_content_id').val());
+}
$::form = Form->new;
$::auth = SL::Auth->new;
$::instance_conf = SL::InstanceConfiguration->new;
- $::request = { cgi => CGI->new({}) };
+ $::request = SL::Request->new(
+ cgi => CGI->new({}),
+ layout => SL::Layout::None->new,
+ );
die 'cannot reach auth db' unless $::auth->session_tables_present;
--- /dev/null
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use File::Slurp;
+use List::Util qw(first max);
+
+my $file_name = (first { -f } qw(SL/ClientJS.pm ../SL/ClientJS.pm)) || die "ClientJS.pm not found";
+my @actions;
+
+foreach (read_file($file_name)) {
+ chomp;
+
+ next unless (m/^my \%supported_methods/ .. m/^\);/);
+
+ push @actions, [ 'action', $1, $2 ] if m/^\s+([a-zA-Z]+)\s*=>\s*(\d+),$/;
+ push @actions, [ 'comment', $1 ] if m/^\s+#\s+(.+)/;
+}
+
+my $longest = max map { length($_->[1]) } grep { $_->[0] eq 'action' } @actions;
+my $first = 1;
+my $output;
+
+# else if (action[0] == 'hide') $(action[1]).hide();
+foreach my $action (@actions) {
+ if ($action->[0] eq 'comment') {
+ print "\n" unless $first;
+ print " // ", $action->[1], "\n";
+
+ } else {
+ my $args = $action->[2] == 1 ? '' : join(', ', map { "action[$_]" } (2..$action->[2]));
+
+ printf(' %s if (action[0] == \'%s\')%s $(action[1]).%s(%s);' . "\n",
+ $first ? ' ' : 'else',
+ $action->[1],
+ ' ' x ($longest - length($action->[1])),
+ $action->[1],
+ $args);
+ $first = 0;
+ }
+}
+
+printf "\n else\%sconsole.log('Unknown action: ' + action[0]);\n", ' ' x (4 + 2 + 6 + 3 + 4 + 2 + $longest + 1);
--- /dev/null
+-- @tag: drop_dpt_trans
+-- @description: Löscht nicht mehr benötigte Tabelle dpt_trans
+-- @depends: release_3_0_0
+-- @charset: utf-8
+
+-- Drop table dpt_trans:
+DROP TABLE dpt_trans;
+
+-- Drop all Trigger which manage dpt_trans:
+DROP TRIGGER check_department ON ar;
+DROP TRIGGER check_department ON ap;
+DROP TRIGGER check_department ON gl;
+DROP TRIGGER check_department ON oe;
+DROP TRIGGER del_department ON ar;
+DROP TRIGGER del_department ON ap;
+DROP TRIGGER del_department ON gl;
+DROP TRIGGER del_department ON oe;
+
+-- Drop all functions where dpt_trans is used:
+DROP FUNCTION check_department();
+DROP FUNCTION del_department();
--- /dev/null
+-- @tag: drop_gifi
+-- @description: Entfernt Spalten gifi_accno und pos_ustva aus der Tabelle chart. Tabelle gifi wird gelöscht.
+-- @depends: release_3_0_0
+-- @charset: utf-8
+
+ --Lösche Tabelle gifi:
+ DROP TABLE gifi;
+
+ --Lösche Spalte gifi_accno aus chart:
+ ALTER TABLE chart DROP COLUMN gifi_accno;
+
+ --Lösche Spalte pos_ustva aus chart:
+ ALTER TABLE chart DROP COLUMN pos_ustva;
--- /dev/null
+-- @tag: drop_rma
+-- @description: Löscht nicht mehr benötigte Tabellen rma und rma_items
+-- @depends: release_3_0_0
+-- @charset: utf-8
+
+DROP TABLE rma;
+DROP TABLE rmaitems;
-use Test::More tests => 44;
+use Test::More tests => 50;
use Test::Exception;
use strict;
$item = get_item(8); $item->remove_from_list; $item->parent_id(3); $item->add_to_list(position => 'first');
test_positions "add_to_list position 'first' in empty", [ 1, undef, 1 ], [ 2, undef, 2 ], [ 3, 1, 1 ], [ 4, 1, 2 ], [ 5, 1, 3 ], [ 6, 4, 1 ], [ 7, 4, 2 ], [ 8, 3, 1 ];
-
+reset_state();
+$item = get_item(4);
+is($item->get_next_in_list->id, 5, 'Next of 4 is 5');
+is($item->get_previous_in_list->id, 3, 'Previous of 4 is 5');
+is($item->get_next_in_list->get_previous_in_list->id, 4, 'Previous of Next of 4 is 4');
+is($item->get_previous_in_list->get_next_in_list->id, 4, 'Next of Previous of 4 is 4');
+is($item->get_next_in_list->get_next_in_list, undef, 'Next of Next of 4 is undef');
+is($item->get_previous_in_list->get_previous_in_list, undef, 'Previous of Previous of 4 is undef');
# Parametervalidierung
throws_ok { new_item()->move_position_up } qr/not.*been.*saved/i, 'move up not saved yet';
+++ /dev/null
-function fokus(){ [% IF focus %]$('[% focus %]').focus()[% END %] }
+++ /dev/null
-[%- USE T8 %]
-$(function() {
- setupPoints('[% myconfig.numberformat %]', '[% 'wrongformat' | $T8 %]');
- setupDateFormat('[% myconfig.dateformat %]', '[% 'Falsches Datumsformat!' | $T8 %]');
-
- $.datepicker.setDefaults(
- $.extend({}, $.datepicker.regional["[% myconfig.countrycode %]"], {
- dateFormat: "[% datefmt %]",
- showOn: "button",
- showButtonPanel: true,
- changeMonth: true,
- changeYear: true,
- buttonImage: "image/calendar.png",
- buttonImageOnly: true
- }));
-
- $('.datepicker').each(function() {
- $(this).datepicker();
- });
-})
--- /dev/null
+[%- USE T8 %]
+$(function() {
+[% IF datefmt %]
+ setupPoints('[% MYCONFIG.numberformat %]', '[% 'wrongformat' | $T8 %]');
+ setupDateFormat('[% MYCONFIG.dateformat %]', '[% 'Falsches Datumsformat!' | $T8 %]');
+
+ $.datepicker.setDefaults(
+ $.extend({}, $.datepicker.regional["[% MYCONFIG.countrycode %]"], {
+ dateFormat: "[% datefmt %]",
+ showOn: "button",
+ showButtonPanel: true,
+ changeMonth: true,
+ changeYear: true,
+ buttonImage: "image/calendar.png",
+ buttonImageOnly: true
+ }));
+
+ $('.datepicker').each(function() {
+ $(this).datepicker();
+ });
+[% END %]
+
+[% IF ajax_spinner %]
+ $(document).ajaxSend(function() {
+ $('#ajax-spinner').show();
+ }).ajaxStop(function() {
+ $('#ajax-spinner').hide();
+ });
+[% END %]
+});
+
+function fokus() {
+[%- IF focus -%]
+ $('[% focus %]').focus();
+[%- END -%]
+}
-[%- USE T8 %]
+[%- USE T8 %][%- USE LxERP -%]
<div id="frame-header">
[% UNLESS is_links %]
<span class="frame-header-element frame-header-left">
[% now.to_lxoffice %] -
[% now.hms %]
</span>
+ <span class="frame-header-element frame-header-right" id="ajax-spinner">
+ <img src="image/[% IF MYCONFIG.stylesheet == 'lx-office-erp.css' %]spinner-blue.gif[% ELSE %]spinner-white.gif[% END %]" alt="[% LxERP.t8('Loading...') %]">
+ </span>
</div>
[%- USE T8 %]
-[% USE HTML %]
+[% USE HTML %][%- USE LxERP -%]
<script type="text/javascript">
<!--
function clockon() {
<a href="controller.pl?action=LoginScreen/logout" target="_top">[% 'logout' | $T8 %]</a>]
[% date %] <span id='clock_id' style='position:relative'></span>
</span>
+ <span class="frame-header-element frame-header-right" id="ajax-spinner">
+ <img src="image/[% IF MYCONFIG.stylesheet == 'lx-office-erp.css' %]spinner-blue.gif[% ELSE %]spinner-white.gif[% END %]" alt="[% LxERP.t8('Loading...') %]">
+ </span>
</div>
<div id="main_menu_div"></div>
[%- USE T8 %]
-[% USE HTML %]
+[% USE HTML %][%- USE LxERP -%]
<script type="text/javascript" src="js/quicksearch_input.js"></script>
<script type="text/javascript">
<!--
<a href="controller.pl?action=LoginScreen/logout" target="_top">[% 'logout' | $T8 %]</a>]
[% date %] <span id='clock_id' style='position:relative'></span>
</span>
+ <span class="frame-header-element frame-header-right" id="ajax-spinner">
+ <img src="image/[% IF MYCONFIG.stylesheet == 'lx-office-erp.css' %]spinner-blue.gif[% ELSE %]spinner-white.gif[% END %]" alt="[% LxERP.t8('Loading...') %]">
+ </span>
</div>
<div id="menuv3">