Revision 168836cf
Von Moritz Bunkus vor mehr als 11 Jahren hinzugefügt
SL/Controller/RecordLinks.pm | ||
---|---|---|
4 | 4 |
|
5 | 5 |
use parent qw(SL::Controller::Base); |
6 | 6 |
|
7 |
use List::Util qw(first); |
|
8 |
|
|
9 |
use SL::DB::Helper::Mappings; |
|
7 | 10 |
use SL::DB::Order; |
8 | 11 |
use SL::DB::DeliveryOrder; |
9 | 12 |
use SL::DB::Invoice; |
10 | 13 |
use SL::DB::PurchaseInvoice; |
14 |
use SL::DB::RecordLink; |
|
15 |
use SL::JSON; |
|
11 | 16 |
use SL::Locale::String; |
12 | 17 |
|
13 |
__PACKAGE__->run_before('check_object_params', only => [ qw(ajax_list ajax_delete) ]); |
|
18 |
use Rose::Object::MakeMethods::Generic |
|
19 |
( |
|
20 |
scalar => [ qw(object object_model object_id link_type link_direction link_type_desc) ], |
|
21 |
); |
|
22 |
|
|
23 |
__PACKAGE__->run_before('check_object_params', only => [ qw(ajax_list ajax_delete ajax_add_select_type ajax_add_filter ajax_add_list ajax_add_do) ]); |
|
24 |
__PACKAGE__->run_before('check_link_params', only => [ qw( ajax_add_list ajax_add_do) ]); |
|
25 |
|
|
26 |
my @link_types = ( |
|
27 |
{ title => t8('Sales quotation'), type => 'sales_quotation', model => 'Order', number => 'quonumber', }, |
|
28 |
{ title => t8('Sales Order'), type => 'sales_order', model => 'Order', number => 'ordnumber', }, |
|
29 |
{ title => t8('Sales delivery order'), type => 'sales_delivery_order', model => 'DeliveryOrder', number => 'donumber', }, |
|
30 |
{ title => t8('Sales Invoice'), type => 'invoice', model => 'Invoice', number => 'invnumber', }, |
|
31 |
{ title => t8('Request for Quotation'), type => 'request_quotation', model => 'Order', number => 'quonumber', }, |
|
32 |
{ title => t8('Purchase Order'), type => 'purchase_order', model => 'Order', number => 'ordnumber', }, |
|
33 |
{ title => t8('Purchase delivery order'), type => 'purchase_delivery_order', model => 'DeliveryOrder', number => 'donumber', }, |
|
34 |
{ title => t8('Purchase Invoice'), type => 'purchase_invoice', model => 'PurchaseInvoice', number => 'invnumber', }, |
|
35 |
); |
|
36 |
|
|
14 | 37 |
|
15 | 38 |
# |
16 | 39 |
# actions |
... | ... | |
20 | 43 |
my ($self) = @_; |
21 | 44 |
|
22 | 45 |
eval { |
23 |
my $model = 'SL::DB::' . $::form->{object_model}; |
|
24 |
my $object = $model->new(id => $::form->{object_id})->load || die $::locale->text("Record not found"); |
|
25 |
my $linked_records = $object->linked_records(direction => 'both'); |
|
46 |
my $linked_records = $self->object->linked_records(direction => 'both'); |
|
26 | 47 |
my $output = SL::Presenter->get->grouped_record_list( |
27 | 48 |
$linked_records, |
28 | 49 |
with_columns => [ qw(record_link_direction) ], |
29 | 50 |
edit_record_links => 1, |
30 |
object_model => $::form->{object_model},
|
|
31 |
object_id => $::form->{object_id},
|
|
51 |
object_model => $self->object_model,
|
|
52 |
object_id => $self->object_id,
|
|
32 | 53 |
); |
33 | 54 |
$self->render(\$output, { layout => 0, process => 0 }); |
34 | 55 |
|
... | ... | |
41 | 62 |
sub action_ajax_delete { |
42 | 63 |
my ($self) = @_; |
43 | 64 |
|
44 |
my $prefix = $::form->{form_prefix} || 'record_links'; |
|
45 |
foreach my $str (@{ $::form->{"${prefix}_delete"} || [] }) { |
|
65 |
foreach my $str (@{ $::form->{record_links_delete} || [] }) { |
|
46 | 66 |
my ($from_table, $from_id, $to_table, $to_id) = split m/__/, $str, 4; |
47 | 67 |
$from_id *= 1; |
48 | 68 |
$to_id *= 1; |
49 | 69 |
|
50 | 70 |
next if !$from_table || !$from_id || !$to_table || !$to_id; |
51 | 71 |
|
52 |
# $::lxdebug->message(0, "INSERT INTO record_links (from_table, from_id, to_table, to_id) VALUES ('${from_table}', ${from_id}, '${to_table}', ${to_id});"); |
|
53 |
|
|
54 | 72 |
SL::DB::Manager::RecordLink->delete_all(where => [ |
55 | 73 |
from_table => $from_table, |
56 | 74 |
from_id => $from_id, |
... | ... | |
62 | 80 |
$self->action_ajax_list; |
63 | 81 |
} |
64 | 82 |
|
83 |
sub action_ajax_add_filter { |
|
84 |
my ($self) = @_; |
|
85 |
|
|
86 |
my $presenter = $self->presenter; |
|
87 |
|
|
88 |
my @link_type_select = map { [ $_->{type}, $_->{title} ] } @link_types; |
|
89 |
my @projects = map { [ $_->id, $presenter->project($_, display => 'inline', style => 'both', no_link => 1) ] } @{ SL::DB::Manager::Project->get_all_sorted }; |
|
90 |
my $is_sales = $self->object->can('customer_id') && $self->object->customer_id; |
|
91 |
|
|
92 |
$self->render( |
|
93 |
'record_links/add_filter', |
|
94 |
{ layout => 0 }, |
|
95 |
is_sales => $is_sales, |
|
96 |
DEFAULT_LINK_TYPE => $is_sales ? 'sales_quotation' : 'request_quotation', |
|
97 |
LINK_TYPES => \@link_type_select, |
|
98 |
PROJECTS => \@projects, |
|
99 |
); |
|
100 |
} |
|
101 |
|
|
102 |
sub action_ajax_add_list { |
|
103 |
my ($self) = @_; |
|
104 |
|
|
105 |
my $manager = 'SL::DB::Manager::' . $self->link_type_desc->{model}; |
|
106 |
my $vc = $self->link_type =~ m/sales_|^invoice$/ ? 'customer' : 'vendor'; |
|
107 |
|
|
108 |
my @where = $manager->type_filter($self->link_type); |
|
109 |
push @where, ("${vc}.${vc}number" => { ilike => '%' . $::form->{vc_number} . '%' }) if $::form->{vc_number}; |
|
110 |
push @where, ("${vc}.name" => { ilike => '%' . $::form->{vc_name} . '%' }) if $::form->{vc_name}; |
|
111 |
push @where, (transaction_description => { ilike => '%' . $::form->{transaction_description} . '%' }) if $::form->{transaction_description}; |
|
112 |
push @where, (globalproject_id => $::form->{globalproject_id}) if $::form->{globalproject_id}; |
|
113 |
|
|
114 |
my $objects = $manager->get_all_sorted(where => \@where, with_objects => [ $vc, 'globalproject' ]); |
|
115 |
my $output = $self->render( |
|
116 |
'record_links/add_list', |
|
117 |
{ output => 0 }, |
|
118 |
OBJECTS => $objects, |
|
119 |
vc => $vc, |
|
120 |
number_column => $self->link_type_desc->{number}, |
|
121 |
); |
|
122 |
|
|
123 |
my %result = ( count => scalar(@{ $objects }), html => $output ); |
|
124 |
|
|
125 |
$self->render(\to_json(\%result), { type => 'json', process => 0 }); |
|
126 |
} |
|
127 |
|
|
128 |
sub action_ajax_add_do { |
|
129 |
my ($self, %params) = @_; |
|
130 |
|
|
131 |
my $object_side = $self->link_direction eq 'from' ? 'from' : 'to'; |
|
132 |
my $link_side = $object_side eq 'from' ? 'to' : 'from'; |
|
133 |
my $link_table = SL::DB::Helper::Mappings::get_table_for_package($self->link_type_desc->{model}); |
|
134 |
|
|
135 |
foreach my $link_id (@{ $::form->{link_id} || [] }) { |
|
136 |
# Check for existing reverse connections in order to avoid loops. |
|
137 |
my @props = ( |
|
138 |
"${link_side}_table" => $self->object->meta->table, |
|
139 |
"${link_side}_id" => $self->object_id, |
|
140 |
"${object_side}_table" => $link_table, |
|
141 |
"${object_side}_id" => $link_id, |
|
142 |
); |
|
143 |
|
|
144 |
my $existing = SL::DB::Manager::RecordLink->get_all(where => \@props, limit => 1)->[0]; |
|
145 |
next if $existing; |
|
146 |
|
|
147 |
# Check for existing connections in order to avoid duplicates. |
|
148 |
@props = ( |
|
149 |
"${object_side}_table" => $self->object->meta->table, |
|
150 |
"${object_side}_id" => $self->object_id, |
|
151 |
"${link_side}_table" => $link_table, |
|
152 |
"${link_side}_id" => $link_id, |
|
153 |
); |
|
154 |
|
|
155 |
$existing = SL::DB::Manager::RecordLink->get_all(where => \@props, limit => 1)->[0]; |
|
156 |
|
|
157 |
SL::DB::RecordLink->new(@props)->save if !$existing; |
|
158 |
} |
|
159 |
|
|
160 |
$self->action_ajax_list; |
|
161 |
} |
|
162 |
|
|
163 |
|
|
65 | 164 |
# |
66 | 165 |
# filters |
67 | 166 |
# |
... | ... | |
69 | 168 |
sub check_object_params { |
70 | 169 |
my ($self) = @_; |
71 | 170 |
|
72 |
return $::form->{object_id} && ($::form->{object_model} =~ m/^(?:Order|DeliveryOrder|Invoice|PurchaseInvoice)$/); |
|
171 |
my %models = map { ($_->{model} => 1 ) } @link_types; |
|
172 |
|
|
173 |
$self->object_id( $::form->{object_id}); |
|
174 |
$self->object_model($::form->{object_model}); |
|
175 |
|
|
176 |
die "Invalid object_model or object_id" if !$self->object_id || !$models{$self->object_model}; |
|
177 |
|
|
178 |
my $model = 'SL::DB::' . $self->object_model; |
|
179 |
$self->object($model->new(id => $self->object_id)->load || die "Record not found"); |
|
180 |
|
|
181 |
return 1; |
|
182 |
} |
|
183 |
|
|
184 |
sub check_link_params { |
|
185 |
my ($self) = @_; |
|
186 |
|
|
187 |
$self->link_type( $::form->{link_type}); |
|
188 |
$self->link_type_desc((first { $_->{type} eq $::form->{link_type} } @link_types) || die "Invalid link_type"); |
|
189 |
$self->link_direction($::form->{link_direction} =~ m/^(?:from|to)$/ ? $::form->{link_direction} : die "Invalid link_direction"); |
|
190 |
|
|
191 |
return 1; |
|
73 | 192 |
} |
74 | 193 |
|
75 | 194 |
1; |
SL/DB/Manager/DeliveryOrder.pm | ||
---|---|---|
2 | 2 |
|
3 | 3 |
use strict; |
4 | 4 |
|
5 |
use SL::DB::Helper::Manager; |
|
6 |
use base qw(SL::DB::Helper::Manager); |
|
5 |
use parent qw(SL::DB::Helper::Manager); |
|
6 |
|
|
7 |
use SL::DB::Helper::Paginated; |
|
8 |
use SL::DB::Helper::Sorted; |
|
7 | 9 |
|
8 | 10 |
sub object_class { 'SL::DB::DeliveryOrder' } |
9 | 11 |
|
... | ... | |
19 | 21 |
die "Unknown type $type"; |
20 | 22 |
} |
21 | 23 |
|
24 |
sub _sort_spec { |
|
25 |
return ( |
|
26 |
default => [ 'transdate', 1 ], |
|
27 |
nulls => { |
|
28 |
transaction_description => 'FIRST', |
|
29 |
customer_name => 'FIRST', |
|
30 |
vendor_name => 'FIRST', |
|
31 |
default => 'LAST', |
|
32 |
}, |
|
33 |
columns => { |
|
34 |
SIMPLE => 'ALL', |
|
35 |
customer => 'customer.name', |
|
36 |
vendor => 'vendor.name', |
|
37 |
globalprojectnumber => 'lower(globalproject.projectnumber)', |
|
38 |
|
|
39 |
# Bug in Rose::DB::Object: the next should be |
|
40 |
# "globalproject.project_type.description". This workaround will |
|
41 |
# only work if no other table with "project_type" is visible in |
|
42 |
# the current query |
|
43 |
globalproject_type => 'lower(project_type.description)', |
|
44 |
|
|
45 |
map { ( $_ => "lower(delivery_orders.$_)" ) } qw(donumber ordnumber cusordnumber oreqnumber shippingpoint shipvia notes intnotes transaction_description), |
|
46 |
}); |
|
47 |
} |
|
48 |
|
|
49 |
sub default_objects_per_page { 40 } |
|
50 |
|
|
22 | 51 |
1; |
SL/DB/Manager/Invoice.pm | ||
---|---|---|
2 | 2 |
|
3 | 3 |
use strict; |
4 | 4 |
|
5 |
use base qw(SL::DB::Helper::Manager); |
|
5 |
use parent qw(SL::DB::Helper::Manager); |
|
6 |
|
|
7 |
use SL::DB::Helper::Paginated; |
|
8 |
use SL::DB::Helper::Sorted; |
|
6 | 9 |
|
7 | 10 |
sub object_class { 'SL::DB::Invoice' } |
8 | 11 |
|
... | ... | |
13 | 16 |
my $type = lc(shift || ''); |
14 | 17 |
|
15 | 18 |
return (or => [ invoice => 0, invoice => undef ]) if $type eq 'ar_transaction'; |
16 |
return (and => [ invoice => 1, amount => { ge => 0 }, or => [ storno => 0, storno => undef ] ]) if $type eq 'invoice';
|
|
19 |
return (and => [ invoice => 1, amount => { ge => 0 }, or => [ storno => 0, storno => undef ] ]) if $type =~ m/^(?:sales_)?invoice$/;
|
|
17 | 20 |
return (and => [ invoice => 1, amount => { lt => 0 }, or => [ storno => 0, storno => undef ] ]) if $type eq 'credit_note'; |
18 | 21 |
return (and => [ invoice => 1, amount => { lt => 0 }, storno => 1 ]) if $type =~ m/(?:invoice_)?storno/; |
19 | 22 |
return (and => [ invoice => 1, amount => { ge => 0 }, storno => 1 ]) if $type eq 'credit_note_storno'; |
... | ... | |
21 | 24 |
die "Unknown type $type"; |
22 | 25 |
} |
23 | 26 |
|
27 |
sub _sort_spec { |
|
28 |
return ( |
|
29 |
default => [ 'transdate', 1 ], |
|
30 |
nulls => { |
|
31 |
transaction_description => 'FIRST', |
|
32 |
customer_name => 'FIRST', |
|
33 |
default => 'LAST', |
|
34 |
}, |
|
35 |
columns => { |
|
36 |
SIMPLE => 'ALL', |
|
37 |
customer => 'customer.name', |
|
38 |
globalprojectnumber => 'lower(globalproject.projectnumber)', |
|
39 |
|
|
40 |
# Bug in Rose::DB::Object: the next should be |
|
41 |
# "globalproject.project_type.description". This workaround will |
|
42 |
# only work if no other table with "project_type" is visible in |
|
43 |
# the current query |
|
44 |
globalproject_type => 'lower(project_type.description)', |
|
45 |
|
|
46 |
map { ( $_ => "lower(ar.$_)" ) } qw(invnumber ordnumber quonumber cusordnumber shippingpoint shipvia notes intnotes transaction_description), |
|
47 |
}); |
|
48 |
} |
|
49 |
|
|
50 |
sub default_objects_per_page { 40 } |
|
51 |
|
|
24 | 52 |
1; |
SL/DB/Manager/Order.pm | ||
---|---|---|
30 | 30 |
nulls => { |
31 | 31 |
transaction_description => 'FIRST', |
32 | 32 |
customer_name => 'FIRST', |
33 |
vendor_name => 'FIRST', |
|
33 | 34 |
default => 'LAST', |
34 | 35 |
}, |
35 | 36 |
columns => { |
36 | 37 |
SIMPLE => 'ALL', |
37 | 38 |
customer => 'customer.name', |
39 |
vendor => 'vendor.name', |
|
38 | 40 |
globalprojectnumber => 'lower(globalproject.projectnumber)', |
39 | 41 |
map { ( $_ => "lower(oe.$_)" ) } qw(ordnumber quonumber cusordnumber shippingpoint shipvia notes intnotes transaction_description), |
40 | 42 |
}); |
SL/DB/Manager/PurchaseInvoice.pm | ||
---|---|---|
2 | 2 |
|
3 | 3 |
use strict; |
4 | 4 |
|
5 |
use SL::DB::Helper::Manager; |
|
6 |
use base qw(SL::DB::Helper::Manager); |
|
5 |
use parent qw(SL::DB::Helper::Manager); |
|
6 |
|
|
7 |
use SL::DB::Helper::Paginated; |
|
8 |
use SL::DB::Helper::Sorted; |
|
7 | 9 |
|
8 | 10 |
sub object_class { 'SL::DB::PurchaseInvoice' } |
9 | 11 |
|
... | ... | |
14 | 16 |
my $type = lc(shift || ''); |
15 | 17 |
|
16 | 18 |
return (or => [ invoice => 0, invoice => undef ]) if $type eq 'ap_transaction'; |
17 |
return (and => [ invoice => 1, or => [ storno => 0, storno => undef ] ]) if $type eq 'invoice';
|
|
19 |
return (and => [ invoice => 1, or => [ storno => 0, storno => undef ] ]) if $type =~ m/^(?:purchase_)?invoice$/;
|
|
18 | 20 |
return (and => [ invoice => 1, storno => 1 ]) if $type =~ m/(?:invoice_)?storno/; |
19 | 21 |
|
20 | 22 |
die "Unknown type $type"; |
21 | 23 |
} |
22 | 24 |
|
25 |
sub _sort_spec { |
|
26 |
return ( |
|
27 |
default => [ 'transdate', 1 ], |
|
28 |
nulls => { |
|
29 |
transaction_description => 'FIRST', |
|
30 |
vendor_name => 'FIRST', |
|
31 |
default => 'LAST', |
|
32 |
}, |
|
33 |
columns => { |
|
34 |
SIMPLE => 'ALL', |
|
35 |
vendor => 'vendor.name', |
|
36 |
globalprojectnumber => 'lower(globalproject.projectnumber)', |
|
37 |
|
|
38 |
# Bug in Rose::DB::Object: the next should be |
|
39 |
# "globalproject.project_type.description". This workaround will |
|
40 |
# only work if no other table with "project_type" is visible in |
|
41 |
# the current query |
|
42 |
globalproject_type => 'lower(project_type.description)', |
|
43 |
|
|
44 |
map { ( $_ => "lower(ap.$_)" ) } qw(invnumber ordnumber quonumber shipvia notes intnotes transaction_description), |
|
45 |
}); |
|
46 |
} |
|
47 |
|
|
48 |
sub default_objects_per_page { 40 } |
|
49 |
|
|
23 | 50 |
1; |
SL/Presenter/Invoice.pm | ||
---|---|---|
24 | 24 |
sub purchase_invoice { |
25 | 25 |
my ($self, $invoice, %params) = @_; |
26 | 26 |
|
27 |
return _is_ir_record($self, $invoice, 'is', %params);
|
|
27 |
return _is_ir_record($self, $invoice, 'ir', %params);
|
|
28 | 28 |
} |
29 | 29 |
|
30 | 30 |
sub ap_transaction { |
SL/Presenter/Record.pm | ||
---|---|---|
20 | 20 |
sub grouped_record_list { |
21 | 21 |
my ($self, $list, %params) = @_; |
22 | 22 |
|
23 |
%params = map { exists $params{$_} ? ($_ => $params{$_}) : () } qw(edit_record_links form_prefix with_columns object_id object_model); |
|
24 |
$params{form_prefix} ||= 'record_links'; |
|
23 |
%params = map { exists $params{$_} ? ($_ => $params{$_}) : () } qw(edit_record_links with_columns object_id object_model); |
|
25 | 24 |
|
26 | 25 |
my %groups = _group_records($list); |
27 | 26 |
my $output = ''; |
... | ... | |
38 | 37 |
$output .= _purchase_invoice_list( $self, $groups{purchase_invoices}, %params) if $groups{purchase_invoices}; |
39 | 38 |
$output .= _ar_transaction_list( $self, $groups{ar_transactions}, %params) if $groups{ar_transactions}; |
40 | 39 |
|
41 |
$output = $self->render('presenter/record/grouped_record_list', %params, output => $output, nownow => DateTime->now) if $output;
|
|
40 |
$output = $self->render('presenter/record/grouped_record_list', %params, output => $output);
|
|
42 | 41 |
|
43 |
return $output || $self->empty_record_list;
|
|
42 |
return $output; |
|
44 | 43 |
} |
45 | 44 |
|
46 | 45 |
sub empty_record_list { |
47 |
my ($self) = @_; |
|
48 |
return $self->render('presenter/record/empty_record_list');
|
|
46 |
my ($self, %params) = @_;
|
|
47 |
return $self->grouped_record_list([], %params);
|
|
49 | 48 |
} |
50 | 49 |
|
51 | 50 |
sub record_list { |
... | ... | |
121 | 120 |
alignment => $data[0]->{columns}->[$_]->{alignment}, |
122 | 121 |
}, (0..scalar(@columns) - 1); |
123 | 122 |
|
124 |
$params{form_prefix} ||= 'record_links'; |
|
125 |
|
|
126 | 123 |
return $self->render( |
127 | 124 |
'presenter/record/record_list', |
128 | 125 |
%params, |
... | ... | |
168 | 165 |
return $self->record_list( |
169 | 166 |
$list, |
170 | 167 |
title => $::locale->text('Sales Quotations'), |
168 |
type => 'sales_quotation', |
|
171 | 169 |
columns => [ |
172 | 170 |
[ $::locale->text('Quotation Date'), 'transdate' ], |
173 | 171 |
[ $::locale->text('Quotation Number'), sub { $self->sales_quotation($_[0], display => 'table-cell') } ], |
... | ... | |
187 | 185 |
return $self->record_list( |
188 | 186 |
$list, |
189 | 187 |
title => $::locale->text('Request Quotations'), |
188 |
type => 'request_quotation', |
|
190 | 189 |
columns => [ |
191 | 190 |
[ $::locale->text('Quotation Date'), 'transdate' ], |
192 |
[ $::locale->text('Quotation Number'), sub { $self->sales_quotation($_[0], display => 'table-cell') } ],
|
|
191 |
[ $::locale->text('Quotation Number'), sub { $self->request_quotation($_[0], display => 'table-cell') } ],
|
|
193 | 192 |
[ $::locale->text('Vendor'), 'vendor' ], |
194 | 193 |
[ $::locale->text('Net amount'), 'netamount' ], |
195 | 194 |
[ $::locale->text('Transaction description'), 'transaction_description' ], |
... | ... | |
206 | 205 |
return $self->record_list( |
207 | 206 |
$list, |
208 | 207 |
title => $::locale->text('Sales Orders'), |
208 |
type => 'sales_order', |
|
209 | 209 |
columns => [ |
210 | 210 |
[ $::locale->text('Order Date'), 'transdate' ], |
211 | 211 |
[ $::locale->text('Order Number'), sub { $self->sales_order($_[0], display => 'table-cell') } ], |
... | ... | |
226 | 226 |
return $self->record_list( |
227 | 227 |
$list, |
228 | 228 |
title => $::locale->text('Purchase Orders'), |
229 |
type => 'purchase_order', |
|
229 | 230 |
columns => [ |
230 | 231 |
[ $::locale->text('Order Date'), 'transdate' ], |
231 |
[ $::locale->text('Order Number'), sub { $self->sales_order($_[0], display => 'table-cell') } ],
|
|
232 |
[ $::locale->text('Order Number'), sub { $self->purchase_order($_[0], display => 'table-cell') } ],
|
|
232 | 233 |
[ $::locale->text('Request for Quotation'), 'quonumber' ], |
233 | 234 |
[ $::locale->text('Vendor'), 'vendor' ], |
234 | 235 |
[ $::locale->text('Net amount'), 'netamount' ], |
... | ... | |
246 | 247 |
return $self->record_list( |
247 | 248 |
$list, |
248 | 249 |
title => $::locale->text('Sales Delivery Orders'), |
250 |
type => 'sales_delivery_order', |
|
249 | 251 |
columns => [ |
250 | 252 |
[ $::locale->text('Delivery Order Date'), 'transdate' ], |
251 | 253 |
[ $::locale->text('Delivery Order Number'), sub { $self->sales_delivery_order($_[0], display => 'table-cell') } ], |
... | ... | |
266 | 268 |
return $self->record_list( |
267 | 269 |
$list, |
268 | 270 |
title => $::locale->text('Purchase Delivery Orders'), |
271 |
type => 'purchase_delivery_order', |
|
269 | 272 |
columns => [ |
270 | 273 |
[ $::locale->text('Delivery Order Date'), 'transdate' ], |
271 |
[ $::locale->text('Delivery Order Number'), sub { $self->sales_delivery_order($_[0], display => 'table-cell') } ],
|
|
274 |
[ $::locale->text('Delivery Order Number'), sub { $self->purchase_delivery_order($_[0], display => 'table-cell') } ],
|
|
272 | 275 |
[ $::locale->text('Order Number'), 'ordnumber' ], |
273 | 276 |
[ $::locale->text('Vendor'), 'vendor' ], |
274 | 277 |
[ $::locale->text('Transaction description'), 'transaction_description' ], |
... | ... | |
286 | 289 |
return $self->record_list( |
287 | 290 |
$list, |
288 | 291 |
title => $::locale->text('Sales Invoices'), |
292 |
type => 'sales_invoice', |
|
289 | 293 |
columns => [ |
290 | 294 |
[ $::locale->text('Invoice Date'), 'transdate' ], |
291 | 295 |
[ $::locale->text('Invoice Number'), sub { $self->sales_invoice($_[0], display => 'table-cell') } ], |
... | ... | |
306 | 310 |
return $self->record_list( |
307 | 311 |
$list, |
308 | 312 |
title => $::locale->text('Purchase Invoices'), |
313 |
type => 'purchase_invoice', |
|
309 | 314 |
columns => [ |
310 | 315 |
[ $::locale->text('Invoice Date'), 'transdate' ], |
311 |
[ $::locale->text('Invoice Number'), sub { $self->sales_invoice($_[0], display => 'table-cell') } ],
|
|
316 |
[ $::locale->text('Invoice Number'), sub { $self->purchase_invoice($_[0], display => 'table-cell') } ],
|
|
312 | 317 |
[ $::locale->text('Request for Quotation Number'), 'quonumber' ], |
313 | 318 |
[ $::locale->text('Order Number'), 'ordnumber' ], |
314 | 319 |
[ $::locale->text('Vendor'), 'vendor' ], |
... | ... | |
326 | 331 |
return $self->record_list( |
327 | 332 |
$list, |
328 | 333 |
title => $::locale->text('AR Transactions'), |
334 |
type => 'ar_transaction', |
|
329 | 335 |
columns => [ |
330 | 336 |
[ $::locale->text('Invoice Date'), 'transdate' ], |
331 | 337 |
[ $::locale->text('Invoice Number'), sub { $self->ar_transaction($_[0], display => 'table-cell') } ], |
... | ... | |
344 | 350 |
return $self->record_list( |
345 | 351 |
$list, |
346 | 352 |
title => $::locale->text('AP Transactions'), |
353 |
type => 'ap_transaction', |
|
347 | 354 |
columns => [ |
348 | 355 |
[ $::locale->text('Invoice Date'), 'transdate' ], |
349 |
[ $::locale->text('Invoice Number'), sub { $self->ar_transaction($_[0 ], display => 'table-cell') } ],
|
|
356 |
[ $::locale->text('Invoice Number'), sub { $self->ap_transaction($_[0 ], display => 'table-cell') } ],
|
|
350 | 357 |
[ $::locale->text('Vendor'), 'vendor' ], |
351 | 358 |
[ $::locale->text('Net amount'), 'netamount' ], |
352 | 359 |
[ $::locale->text('Paid'), 'paid' ], |
css/presenter/record/record_list.css | ||
---|---|---|
1 |
/* the overlayed element */ |
|
2 |
.record_list_overlay { |
|
3 |
position: fixed; |
|
4 |
top: 50%; |
|
5 |
margin-top: -250px; |
|
6 |
height: 500px; |
|
7 |
|
|
8 |
left: 50%; |
|
9 |
margin-left: -400px; |
|
10 |
width: 800px; |
|
11 |
|
|
12 |
background-color: #fff; |
|
13 |
border: 1px solid #333; |
|
14 |
|
|
15 |
/* CSS3 styling for latest browsers */ |
|
16 |
box-shadow: 0 0 90px 5px #000; |
|
17 |
-moz-box-shadow: 0 0 90px 5px #000; |
|
18 |
-webkit-box-shadow: 0 0 90px #000; |
|
19 |
|
|
20 |
padding: 10px; |
|
21 |
} |
|
22 |
|
|
23 |
.record_list_overlay .overlay_content { |
|
24 |
width: 790px; |
|
25 |
height: 490px; |
|
26 |
overflow: auto; |
|
27 |
} |
|
28 |
|
|
29 |
.record_list_overlay .close { |
|
30 |
background-image: url(../../../image/dialog-close.png); |
|
31 |
position: absolute; |
|
32 |
right: -16px; |
|
33 |
top: -16px; |
|
34 |
cursor: pointer; |
|
35 |
height: 32px; |
|
36 |
width: 32px; |
|
37 |
} |
locale/de/all | ||
---|---|---|
152 | 152 |
'Add and edit units' => 'Einheiten erfassen und bearbeiten', |
153 | 153 |
'Add bank account' => 'Bankkonto erfassen', |
154 | 154 |
'Add custom variable' => 'Benutzerdefinierte Variable erfassen', |
155 |
'Add link: select records to link with' => 'Verknüpfungen hinzufügen: zu verknüpfende Belege auswählen', |
|
156 |
'Add links' => 'Verknüpfungen hinzufügen', |
|
155 | 157 |
'Add note' => 'Notiz erfassen', |
156 | 158 |
'Add unit' => 'Einheit hinzufügen', |
157 | 159 |
'Address' => 'Adresse', |
... | ... | |
209 | 211 |
'Are you sure you want to delete this payment term?' => 'Wollen Sie diese Zahlungsbedingungen wirklich löschen?', |
210 | 212 |
'Are you sure you want to remove the marked entries from the queue?' => 'Sind Sie sicher, dass die markierten Einträge von der Warteschlange gelöscht werden sollen?', |
211 | 213 |
'Are you sure you want to update the prices' => 'Sind Sie sicher, dass Sie die Preise aktualisieren wollen?', |
214 |
'Are you sure?' => 'Sind Sie sicher?', |
|
212 | 215 |
'Article Code' => 'Artikelkürzel', |
213 | 216 |
'Article Code missing!' => 'Artikelkürzel fehlt', |
214 | 217 |
'Article type (see below)' => 'Artikeltyp (siehe unten)', |
... | ... | |
541 | 544 |
'Customer/Vendor' => 'Kunde/Lieferant', |
542 | 545 |
'Customer/Vendor (database ID)' => 'Kunde/Lieferant (Datenbank-ID)', |
543 | 546 |
'Customer/Vendor Name' => 'Kunde/Lieferant', |
544 |
'Customer/Vendor Number' => 'Kundennummer/Lieferantennummer',
|
|
547 |
'Customer/Vendor Number' => 'Kunden-/Lieferantennummer',
|
|
545 | 548 |
'Customername' => 'Kundenname', |
546 | 549 |
'Customernumberinit' => 'Kunden-/Lieferantennummernkreis', |
547 | 550 |
'Customers' => 'Kunden', |
... | ... | |
1127 | 1130 |
'Line and column' => 'Zeile und Spalte', |
1128 | 1131 |
'Line endings' => 'Zeilenumbrüche', |
1129 | 1132 |
'Link direction' => 'Verknüpfungsrichtung', |
1133 |
'Link to' => 'Verknüpfen mit', |
|
1130 | 1134 |
'Linked Records' => 'Verknüpfte Belege', |
1131 | 1135 |
'List Accounts' => 'Konten anzeigen', |
1132 | 1136 |
'List Languages' => 'Sprachen anzeigen', |
... | ... | |
1569 | 1573 |
'Reconciliation' => 'Kontenabgleich', |
1570 | 1574 |
'Record Vendor Invoice' => 'Einkaufsrechnung erfassen', |
1571 | 1575 |
'Record in' => 'Buchen auf', |
1572 |
'Record not found' => 'Objekt nicht gefunden', |
|
1573 | 1576 |
'Recorded Tax' => 'Gespeicherte Steuern', |
1574 | 1577 |
'Recorded taxkey' => 'Gespeicherter Steuerschlüssel', |
1575 | 1578 |
'Reference' => 'Referenz', |
... | ... | |
1676 | 1679 |
'Save settings as' => 'Einstellungen speichern unter', |
1677 | 1680 |
'Saving the file \'%s\' failed. OS error message: %s' => 'Das Speichern der Datei \'%s\' schlug fehl. Fehlermeldung des Betriebssystems: %s', |
1678 | 1681 |
'Screen' => 'Bildschirm', |
1682 |
'Search' => 'Suchen', |
|
1679 | 1683 |
'Search AP Aging' => 'Offene Verbindlichkeiten', |
1680 | 1684 |
'Search AR Aging' => 'Offene Forderungen', |
1681 | 1685 |
'Search contacts' => 'Ansprechpersonensuche', |
... | ... | |
1965 | 1969 |
'The end date is the last day for which invoices will possibly be created.' => 'Das Enddatum ist das letztmögliche Datum, an dem eine Rechnung erzeugt wird.', |
1966 | 1970 |
'The execution schedule is invalid.' => 'Der Ausführungszeitplan ist ungültig.', |
1967 | 1971 |
'The execution type is invalid.' => 'Der Ausführungstyp ist ungültig.', |
1972 |
'The existing record has been created from the link target to add.' => 'Der bestehende Beleg wurde aus dem auszuwählenden Verknüpfungsziel erstellt.', |
|
1968 | 1973 |
'The factor is missing in row %d.' => 'Der Faktor fehlt in Zeile %d.', |
1969 | 1974 |
'The factor is missing.' => 'Der Faktor fehlt.', |
1970 | 1975 |
'The first reason is that kivitendo contained a bug which resulted in the wrong taxkeys being recorded for transactions in which two entries are posted for the same chart with different taxkeys.' => 'Der erste Grund war ein Fehler in kivitendo, der dazu führte, dass bei einer Transaktion, bei der zwei Buchungen mit unterschiedlichen Steuerschlüsseln auf dasselbe Konto durchgeführt wurden, die falschen Steuerschlüssel gespeichert wurden.', |
... | ... | |
1987 | 1992 |
'The group memberships have been saved.' => 'Die Gruppenmitgliedschaften wurden gespeichert.', |
1988 | 1993 |
'The group name is missing.' => 'Der Gruppenname fehlt.', |
1989 | 1994 |
'The items are imported accoring do their number "X" regardless of the column order inside the file.' => 'Die Einträge werden in der Reihenfolge ihrer Indizes "X" unabhängig von der Spaltenreihenfolge in der Datei importiert.', |
1995 |
'The link target to add has been created from the existing record.' => 'Das auszuwählende Verknüpfungsziel wurde aus dem bestehenden Beleg erstellt.', |
|
1990 | 1996 |
'The list has been printed.' => 'Die Liste wurde ausgedruckt.', |
1991 | 1997 |
'The long description is missing.' => 'Der Langtext fehlt.', |
1992 | 1998 |
'The name in row %d has already been used before.' => 'Der Name in Zeile %d wurde vorher bereits benutzt.', |
templates/webpages/presenter/record/empty_record_list.html | ||
---|---|---|
1 |
[% USE LxERP %] |
|
2 |
<p class="message_hint">[% LxERP.t8('No data was found.') %]</p> |
templates/webpages/presenter/record/grouped_record_list.html | ||
---|---|---|
1 | 1 |
[%- USE LxERP -%][%- USE L -%][%- USE HTML -%][%- USE JavaScript -%] |
2 | 2 |
|
3 |
<div id="[% form_prefix %]_list"> |
|
4 |
<p>[% nownow %]</p> |
|
3 |
<div id="record_links_list"> |
|
4 |
[%- IF output %] |
|
5 |
[% output %] |
|
6 |
[%- ELSE %] |
|
7 |
<p class="message_hint">[% LxERP.t8('No data was found.') %]</p> |
|
8 |
[%- END %] |
|
5 | 9 |
|
6 |
[% output %] |
|
7 |
|
|
8 |
[%- IF edit_record_links %] |
|
9 |
<div> |
|
10 |
[% L.button_tag(form_prefix _ '_delete()', LxERP.t8('Delete links')) %] |
|
11 |
</div> |
|
10 |
[%- IF edit_record_links %] |
|
11 |
<div> |
|
12 |
[% L.button_tag('record_links_add()', LxERP.t8('Add links')) %] |
|
13 |
[% IF output %] |
|
14 |
[% L.button_tag('record_links_delete()', LxERP.t8('Delete links')) %] |
|
15 |
[%- END %] |
|
16 |
</div> |
|
12 | 17 |
|
13 | 18 |
<script type="text/javascript"> |
14 | 19 |
<!-- |
15 |
function [% form_prefix %]_delete() { |
|
16 |
var checkboxes = $('.record_links_delete').filter(function () { return $(this).attr('checked'); }); |
|
20 |
$(function() { |
|
21 |
|
|
22 |
}); |
|
23 |
|
|
24 |
function record_links_add() { |
|
25 |
var url = "controller.pl?action=RecordLinks/ajax_add_filter&object_model=[% JavaScript.escape(object_model) %]&object_id=[% JavaScript.escape(object_id) %]&"; |
|
26 |
var id = 'record_links_add'; |
|
27 |
|
|
28 |
$('#' + id).remove(); |
|
29 |
var div = $('<div id="' + id + '" class="jqmWindow record_list_overlay"></div>').hide().appendTo('body'); |
|
30 |
var close = $('<div class="close"></div>').appendTo(div); |
|
31 |
var content = $('<div class="overlay_content"></div>').appendTo(div); |
|
32 |
div.jqm({ modal: true }); |
|
33 |
div.jqmShow(); |
|
34 |
$.ajax({ url: url, success: function(new_html) { $(content).html(new_html); } }); |
|
35 |
$(close).click(function() { |
|
36 |
div.jqmHide(); |
|
37 |
div.remove(); |
|
38 |
}); |
|
39 |
} |
|
40 |
|
|
41 |
function record_links_delete() { |
|
42 |
var checkboxes = $('.record_links_delete').filter(function () { return $(this).prop('checked'); }); |
|
17 | 43 |
|
18 | 44 |
if ((checkboxes.size() == 0) || !confirm('[% LxERP.t8('Do you really want to delete the selected links?') %]')) |
19 | 45 |
return false; |
... | ... | |
27 | 53 |
$.ajax({ |
28 | 54 |
url: "controller.pl?" + checkboxes.serialize(), |
29 | 55 |
data: data, |
30 |
success: function(new_data) { $('#[% form_prefix %]_list').replaceWith(new_data); }
|
|
56 |
success: function(new_data) { $('#record_links_list').replaceWith(new_data); }
|
|
31 | 57 |
}); |
32 | 58 |
|
33 | 59 |
return false; |
templates/webpages/presenter/record/record_list.html | ||
---|---|---|
2 | 2 |
<div class="listtop">[%- P.escape(title) %]</div> |
3 | 3 |
|
4 | 4 |
<div style="padding-bottom: 15px"> |
5 |
<table style="width: 100%"> |
|
5 |
<table style="width: 100%" id="record_list_[% type %]">
|
|
6 | 6 |
<thead> |
7 | 7 |
<tr> |
8 |
[%- IF edit_record_links %]<th class="listheading"></th>[%- END %] |
|
8 |
[%- IF edit_record_links %] |
|
9 |
<th class="listheading">[% L.checkbox_tag('record_links_delete_checkall_' _ type) %]</th> |
|
10 |
[%- END %] |
|
9 | 11 |
[%- FOREACH column = TABLE_HEADER %] |
10 | 12 |
<th class="listheading"[% IF column.alignment %] align="[% column.alignment %]"[% END %]>[%- P.escape(column.value) %]</th> |
11 | 13 |
[%- END %] |
... | ... | |
16 | 18 |
[%- FOREACH row = TABLE_ROWS %] |
17 | 19 |
<tr class="listrow[% loop.count % 2 %]"> |
18 | 20 |
[%- IF edit_record_links %] |
19 |
<td>[%- L.checkbox_tag(form_prefix _ '_delete[]', 'value'=row.record_link.from_table _ '__' _ row.record_link.from_id _ '__' _ row.record_link.to_table _ '__' _ row.record_link.to_id, 'class'='record_links_delete') %]</td>
|
|
21 |
<td>[%- L.checkbox_tag('record_links_delete[]', 'value'=row.record_link.from_table _ '__' _ row.record_link.from_id _ '__' _ row.record_link.to_table _ '__' _ row.record_link.to_id, 'class'='record_links_delete') %]</td>
|
|
20 | 22 |
[%- END %] |
21 | 23 |
[%- FOREACH column = row.columns %] |
22 | 24 |
<td[% IF column.alignment %] align="[% column.alignment %]"[% END %]> |
... | ... | |
30 | 32 |
</tbody> |
31 | 33 |
</table> |
32 | 34 |
</div> |
35 |
|
|
36 |
[% IF edit_record_links %] |
|
37 |
<script type="text/javascript"> |
|
38 |
$('#record_links_delete_checkall_[% type %]').checkall("#record_list_[% type %] tbody :checkbox"); |
|
39 |
</script> |
|
40 |
[%- END %] |
templates/webpages/record_links/add_filter.html | ||
---|---|---|
1 |
[%- USE L -%][%- USE LxERP -%][%- USE JavaScript -%] |
|
2 |
[%- SET style='width: 500px' %] |
|
3 |
<div class="listtop">[%- LxERP.t8("Add link: select records to link with") %]</div> |
|
4 |
|
|
5 |
|
|
6 |
<form method="post" action="controller.pl"> |
|
7 |
[% L.hidden_tag('object_model', SELF.object_model) %] |
|
8 |
[% L.hidden_tag('object_id', SELF.object_id) %] |
|
9 |
|
|
10 |
<table> |
|
11 |
<tr> |
|
12 |
<td>[%- LxERP.t8("Link to") %]:</td> |
|
13 |
<td>[% L.select_tag('link_type', LINK_TYPES, default=DEFAULT_LINK_TYPE, style=style) %]</td> |
|
14 |
</tr> |
|
15 |
|
|
16 |
<tr> |
|
17 |
<td>[%- LxERP.t8("Link direction") %]:</td> |
|
18 |
<td>[% L.select_tag('link_direction', |
|
19 |
[ [ 'from', LxERP.t8("The link target to add has been created from the existing record."), ], |
|
20 |
[ 'to', LxERP.t8("The existing record has been created from the link target to add."), ], ], |
|
21 |
style=style) %]</td> |
|
22 |
</tr> |
|
23 |
|
|
24 |
<tr> |
|
25 |
<td>[%- LxERP.t8("Customer/Vendor Number") %]:</td> |
|
26 |
<td>[% L.input_tag('vc_number', is_sales ? SELF.object.customer.customernumber : SELF.object.vendor.vendornumber, style=style) %]</td> |
|
27 |
</tr> |
|
28 |
|
|
29 |
<tr> |
|
30 |
<td>[%- LxERP.t8("Customer/Vendor Name") %]:</td> |
|
31 |
<td>[% L.input_tag('vc_name', is_sales ? SELF.object.customer.name : SELF.object.vendor.name, style=style) %]</td> |
|
32 |
</tr> |
|
33 |
|
|
34 |
<tr> |
|
35 |
<td>[%- LxERP.t8("Project") %]:</td> |
|
36 |
<td>[% L.select_tag('project_id', PROJECTS, default=SELF.object.globalproject_id, with_empty=1, style=style) %]</td> |
|
37 |
</tr> |
|
38 |
|
|
39 |
<tr> |
|
40 |
<td>[%- LxERP.t8("Transaction description") %]:</td> |
|
41 |
<td>[% L.input_tag('transaction_description', '', style=style) %]</td> |
|
42 |
</tr> |
|
43 |
</table> |
|
44 |
|
|
45 |
<p> |
|
46 |
[% L.button_tag('filter_record_links()', LxERP.t8("Search")) %] |
|
47 |
[% L.button_tag('add_selected_record_links()', LxERP.t8("Add links"), id='add_selected_record_links_button', disabled=1) %] |
|
48 |
<a href="#" onclick="record_links_reset_form();">[%- LxERP.t8("Reset") %]</a> |
|
49 |
<a href="#" onclick="record_links_cancel();">[% LxERP.t8("Cancel") %]</a> |
|
50 |
</p> |
|
51 |
|
|
52 |
<hr> |
|
53 |
|
|
54 |
<div id="record_list_filtered_list"></div> |
|
55 |
|
|
56 |
</form> |
|
57 |
|
|
58 |
<script type="text/javascript"> |
|
59 |
<!-- |
|
60 |
$(function() { |
|
61 |
$('.jqmWindow input[name=vc_name]').focus(); |
|
62 |
}); |
|
63 |
|
|
64 |
function record_links_reset_form() { |
|
65 |
$('.jqmWindow form input[type=text]').val(''); |
|
66 |
$('.jqmWindow form select').prop('selectedIndex', 0); |
|
67 |
} |
|
68 |
|
|
69 |
function record_links_cancel() { |
|
70 |
$('.jqmWindow').jqmHide(); |
|
71 |
$('.jqmWindow').remove(); |
|
72 |
} |
|
73 |
|
|
74 |
function filter_record_links() { |
|
75 |
var url="controller.pl?action=RecordLinks/ajax_add_list&" + $(".jqmWindow form").serialize(); |
|
76 |
$.ajax({ |
|
77 |
url: url, |
|
78 |
success: function(new_data) { |
|
79 |
$("#record_list_filtered_list").html(new_data['html']); |
|
80 |
$('#add_selected_record_links_button').prop('disabled', new_data['count'] == 0); |
|
81 |
} |
|
82 |
}); |
|
83 |
} |
|
84 |
|
|
85 |
function add_selected_record_links() { |
|
86 |
var url="controller.pl?action=RecordLinks/ajax_add_do&" + $(".jqmWindow form").serialize(); |
|
87 |
$.ajax({ |
|
88 |
url: url, |
|
89 |
success: function(new_html) { |
|
90 |
$('#record_links_list').replaceWith(new_html); |
|
91 |
record_links_cancel(); |
|
92 |
} |
|
93 |
}); |
|
94 |
} |
|
95 |
--> |
|
96 |
</script> |
templates/webpages/record_links/add_list.html | ||
---|---|---|
1 |
[%- USE T8 -%][%- USE HTML -%][%- USE LxERP -%][%- USE P -%][%- USE L -%] |
|
2 |
[%- IF !OBJECTS.size %] |
|
3 |
<p class="message_hint">[% 'No data was found.' | $T8 %]</p> |
|
4 |
[%- ELSE %] |
|
5 |
<table width="100%"> |
|
6 |
<tr class="listheading"> |
|
7 |
<th>[% L.checkbox_tag('record_links_check_all') %]</th> |
|
8 |
<th>[% IF vc == 'customer' %][%- LxERP.t8("Customer") %][%- ELSE %][%- LxERP.t8("Vendor") %][%- END %]</th> |
|
9 |
<th>[%- LxERP.t8("Number") %]</th> |
|
10 |
<th>[%- LxERP.t8("Date") %]</th> |
|
11 |
<th>[%- LxERP.t8("Transaction description") %]</th> |
|
12 |
<th>[%- LxERP.t8("Project") %]</th> |
|
13 |
</tr> |
|
14 |
|
|
15 |
[%- FOREACH object = OBJECTS %] |
|
16 |
<tr class="listrow[% loop.count % 2 %]"> |
|
17 |
<td>[% L.checkbox_tag('link_id[]', value=object.id) %]</td> |
|
18 |
<td>[%- HTML.escape(object.$vc.name) %]</td> |
|
19 |
<td>[%- HTML.escape(object.$number_column) %]</td> |
|
20 |
<td>[%- HTML.escape(object.transdate.to_kivitendo) %]</td> |
|
21 |
<td>[%- HTML.escape(object.transaction_description) %]</td> |
|
22 |
<td>[%- P.project(object.globalproject, no_link=1) %]</td> |
|
23 |
</tr> |
|
24 |
[%- END %] |
|
25 |
</table> |
|
26 |
|
|
27 |
<script type="text/javascript"> |
|
28 |
<!-- |
|
29 |
$(function() { |
|
30 |
$('#record_links_check_all').checkall('INPUT[name="link_id[]"]'); |
|
31 |
}); |
|
32 |
--> |
|
33 |
</script> |
|
34 |
[%- END %] |
Auch abrufbar als: Unified diff
Verknüpfte Belege: beliebige Verknüpfungen hinzufügen können