Revision ba0fb69c
Von Sven Schöling vor mehr als 12 Jahren hinzugefügt
SL/Controller/Base.pm | ||
---|---|---|
7 | 7 |
use Carp; |
8 | 8 |
use IO::File; |
9 | 9 |
use List::Util qw(first); |
10 |
use SL::Request qw(flatten); |
|
11 |
use SL::MoreCommon qw(uri_encode); |
|
10 | 12 |
|
11 | 13 |
# |
12 | 14 |
# public/helper functions |
... | ... | |
21 | 23 |
my $controller = delete($params{controller}) || $self->_controller_name; |
22 | 24 |
my $action = delete($params{action}) || 'dispatch'; |
23 | 25 |
$params{action} = "${controller}/${action}"; |
24 |
my $query = join('&', map { $::form->escape($_) . '=' . $::form->escape($params{$_}) } keys %params);
|
|
26 |
my $query = join '&', map { uri_encode($_->[0]) . '=' . uri_encode($_->[1]) } @{ flatten(\%params) };
|
|
25 | 27 |
|
26 | 28 |
return "controller.pl?${query}"; |
27 | 29 |
} |
SL/Controller/SellPriceInformation.pm | ||
---|---|---|
1 |
package SL::Controller::SellPriceInformation; |
|
2 |
|
|
3 |
use strict; |
|
4 |
use parent qw(SL::Controller::Base); |
|
5 |
|
|
6 |
use Clone qw(clone); |
|
7 |
use SL::DB::OrderItem; |
|
8 |
use SL::Controller::Helper::ParseFilter; |
|
9 |
use SL::Controller::Helper::ReportGenerator; |
|
10 |
|
|
11 |
sub action_list { |
|
12 |
my ($self) = @_; |
|
13 |
$self->{action} = 'list'; |
|
14 |
|
|
15 |
my %list_params = ( |
|
16 |
sort_by => $::form->{sort_by} || 'reqdate', |
|
17 |
sort_dir => $::form->{sort_dir}, |
|
18 |
filter => $::form->{filter}, |
|
19 |
page => $::form->{page}, |
|
20 |
); |
|
21 |
|
|
22 |
my $db_args = $self->setup_for_list(%list_params); |
|
23 |
$self->{pages} = SL::DB::Manager::OrderItem->paginate(%list_params, args => $db_args, per_page => 5); |
|
24 |
|
|
25 |
my $bottom = $::form->parse_html_template('price_information/report_bottom', { SELF => $self }); |
|
26 |
|
|
27 |
$self->prepare_report( |
|
28 |
report_generator_options => { |
|
29 |
raw_bottom_info_text => $bottom, |
|
30 |
controller_class => 'SellPriceInformation', |
|
31 |
}, |
|
32 |
db_args => $db_args, |
|
33 |
); |
|
34 |
|
|
35 |
$self->{orderitems} = SL::DB::Manager::OrderItem->get_all(%$db_args); |
|
36 |
|
|
37 |
$self->list_objects; |
|
38 |
} |
|
39 |
|
|
40 |
# private functions |
|
41 |
|
|
42 |
sub setup_for_list { |
|
43 |
my ($self, %params) = @_; |
|
44 |
$self->{filter} = _pre_parse_filter($params{filter}); |
|
45 |
|
|
46 |
my %args = ( |
|
47 |
parse_filter($self->{filter}, |
|
48 |
with_objects => [ 'order', 'order.customer', 'part' ], |
|
49 |
), |
|
50 |
sort_by => $self->set_sort_params(%params), |
|
51 |
page => $params{page}, |
|
52 |
); |
|
53 |
|
|
54 |
# $args{query} = [ @{ $args{query} || [] } ]; |
|
55 |
|
|
56 |
return \%args; |
|
57 |
} |
|
58 |
|
|
59 |
sub set_sort_params { |
|
60 |
my ($self, %params) = @_; |
|
61 |
my $sort_str; |
|
62 |
($self->{sort_by}, $self->{sort_dir}, $sort_str) = |
|
63 |
SL::DB::Manager::OrderItem->make_sort_string(%params); |
|
64 |
return $sort_str; |
|
65 |
} |
|
66 |
|
|
67 |
sub prepare_report { |
|
68 |
my ($self, %params) = @_; |
|
69 |
|
|
70 |
my $objects = $params{objects} || []; |
|
71 |
my $report = SL::ReportGenerator->new(\%::myconfig, $::form); |
|
72 |
$self->{report} = $report; |
|
73 |
|
|
74 |
my @columns = qw(orddate ordnumber customer ship qty sellprice discount amount); |
|
75 |
my @visible = qw(orddate ordnumber customer ship qty sellprice discount amount); |
|
76 |
my @sortable = qw(orddate ordnumber customer sellprice discount ); |
|
77 |
|
|
78 |
my %column_defs = ( |
|
79 |
orddate => { text => $::locale->text('Date'), |
|
80 |
sub => sub { $_[0]->order->orddate_as_date }}, |
|
81 |
ordnumber => { text => $::locale->text('Number'), |
|
82 |
sub => sub { $_[0]->order->ordnumber }, |
|
83 |
obj_link => sub { $self->link_to($_[0]->order) }}, |
|
84 |
customer => { text => $::locale->text('Customer'), |
|
85 |
sub => sub { $_[0]->order->customer->name }, |
|
86 |
obj_link => sub { $self->link_to($_[0]->order->customer) }}, |
|
87 |
customer => { text => $::locale->text('Customer'), |
|
88 |
sub => sub { $_[0]->order->customer->name }, |
|
89 |
obj_link => sub { $self->link_to($_[0]->order->customer) }}, |
|
90 |
ship => { text => $::locale->text('Delivered'), |
|
91 |
sub => sub { $::form->format_amount(\%::myconfig, $_[0]->shipped_qty) . ' ' . $_[0]->unit }}, |
|
92 |
qty => { text => $::locale->text('Qty'), |
|
93 |
sub => sub { $_[0]->qty_as_number . ' ' . $_[0]->unit }}, |
|
94 |
sellprice => { text => $::locale->text('Sell Price'), |
|
95 |
sub => sub { $_[0]->sellprice_as_number }}, |
|
96 |
discount => { text => $::locale->text('Discount'), |
|
97 |
sub => sub { $_[0]->discount_as_percent . "%" }}, |
|
98 |
amount => { text => $::locale->text('Amount'), |
|
99 |
sub => sub { $::form->format_amount(\%::myconfig, $_[0]->qty * $_[0]->sellprice * (1 - $_[0]->discount), 2) }}, |
|
100 |
); |
|
101 |
|
|
102 |
for my $col (@sortable) { |
|
103 |
$column_defs{$col}{link} = $self->self_url( |
|
104 |
sort_by => $col, |
|
105 |
sort_dir => ($self->{sort_by} eq $col ? 1 - $self->{sort_dir} : $self->{sort_dir}), |
|
106 |
page => $self->{pages}{cur}, |
|
107 |
); |
|
108 |
} |
|
109 |
|
|
110 |
map { $column_defs{$_}->{visible} = 1 } @visible; |
|
111 |
|
|
112 |
$report->set_columns(%column_defs); |
|
113 |
$report->set_column_order(@columns); |
|
114 |
$report->set_options(allow_pdf_export => 0, allow_csv_export => 0); |
|
115 |
$report->set_sort_indicator(%params); |
|
116 |
$report->set_export_options(@{ $params{report_generator_export_options} || [] }); |
|
117 |
$report->set_options( |
|
118 |
%{ $params{report_generator_options} || {} }, |
|
119 |
output_format => 'HTML', |
|
120 |
top_info_text => $::locale->text('Sales Price Information'), |
|
121 |
title => $::locale->text('Sales Price information'), |
|
122 |
); |
|
123 |
$report->set_options_from_form; |
|
124 |
|
|
125 |
$self->{report_data} = { |
|
126 |
column_defs => \%column_defs, |
|
127 |
columns => \@columns, |
|
128 |
visible => \@visible, |
|
129 |
sortable => \@sortable, |
|
130 |
}; |
|
131 |
} |
|
132 |
|
|
133 |
sub list_objects { |
|
134 |
my ($self) = @_; |
|
135 |
my $column_defs = $self->{report_data}{column_defs}; |
|
136 |
for my $obj (@{ $self->{orderitems} || [] }) { |
|
137 |
$self->{report}->add_data({ |
|
138 |
map { |
|
139 |
$_ => { |
|
140 |
data => $column_defs->{$_}{sub} ? $column_defs->{$_}{sub}->($obj) |
|
141 |
: $obj->can($_) ? $obj->$_ |
|
142 |
: $obj->{$_}, |
|
143 |
link => $column_defs->{$_}{obj_link} ? $column_defs->{$_}{obj_link}->($obj) : '', |
|
144 |
}, |
|
145 |
} @{ $self->{report_data}{columns} || {} } |
|
146 |
}); |
|
147 |
} |
|
148 |
|
|
149 |
return $self->{report}->generate_with_headers; |
|
150 |
} |
|
151 |
|
|
152 |
sub link_to { |
|
153 |
my ($self, $object, %params) = @_; |
|
154 |
|
|
155 |
return unless $object; |
|
156 |
my $action = $params{action} || 'edit'; |
|
157 |
|
|
158 |
if ($object->isa('SL::DB::Order')) { |
|
159 |
my $type = $object->type; |
|
160 |
my $vc = $object->is_sales ? 'customer' : 'vendor'; |
|
161 |
my $id = $object->id; |
|
162 |
|
|
163 |
return "oe.pl?action=$action&type=$type&vc=$vc&id=$id"; |
|
164 |
} |
|
165 |
if ($object->isa('SL::DB::Customer')) { |
|
166 |
my $id = $object->id; |
|
167 |
return "ct.pl?action=$action&id=$id&db=customer"; |
|
168 |
} |
|
169 |
} |
|
170 |
|
|
171 |
sub _pre_parse_filter { |
|
172 |
my $filter = clone(shift); |
|
173 |
|
|
174 |
if ( exists $filter->{order} |
|
175 |
&& exists $filter->{order}{type}) { |
|
176 |
push @{ $filter->{and} }, SL::DB::Manager::Order->type_filter(delete $filter->{order}{type}, "order."), |
|
177 |
} |
|
178 |
|
|
179 |
return $filter; |
|
180 |
} |
|
181 |
|
|
182 |
sub self_url { |
|
183 |
my ($self, %params) = @_; |
|
184 |
%params = ( |
|
185 |
action => $self->{action}, |
|
186 |
sort_by => $self->{sort}, |
|
187 |
sort_dir => $self->{sort_dir}, |
|
188 |
page => $self->{pages}{cur}, |
|
189 |
filter => $::form->{filter}, |
|
190 |
%params, |
|
191 |
); |
|
192 |
|
|
193 |
return $self->url_for(%params); |
|
194 |
} |
|
195 |
|
|
196 |
1; |
SL/DB/Manager/Order.pm | ||
---|---|---|
10 | 10 |
__PACKAGE__->make_manager_methods; |
11 | 11 |
|
12 | 12 |
sub type_filter { |
13 |
my $class = shift; |
|
14 |
my $type = lc(shift || ''); |
|
15 |
|
|
16 |
return (and => [ '!customer_id' => undef, quotation => 1 ]) if $type eq 'sales_quotation'; |
|
17 |
return (and => [ '!vendor_id' => undef, quotation => 1 ]) if $type eq 'request_quotation'; |
|
18 |
return (and => [ '!customer_id' => undef, or => [ quotation => 0, quotation => undef ] ]) if $type eq 'sales_order'; |
|
19 |
return (and => [ '!vendor_id' => undef, or => [ quotation => 0, quotation => undef ] ]) if $type eq 'purchase_order'; |
|
13 |
my $class = shift; |
|
14 |
my $type = lc(shift || ''); |
|
15 |
my $prefix = shift || ''; |
|
16 |
|
|
17 |
return (and => [ "!${prefix}customer_id" => undef, "${prefix}quotation" => 1 ]) if $type eq 'sales_quotation'; |
|
18 |
return (and => [ "!${prefix}vendor_id" => undef, "${prefix}quotation" => 1 ]) if $type eq 'request_quotation'; |
|
19 |
return (and => [ "!${prefix}customer_id" => undef, or => [ "${prefix}quotation" => 0, "${prefix}quotation" => undef ] ]) if $type eq 'sales_order'; |
|
20 |
return (and => [ "!${prefix}vendor_id" => undef, or => [ "${prefix}quotation" => 0, "${prefix}quotation" => undef ] ]) if $type eq 'purchase_order'; |
|
20 | 21 |
|
21 | 22 |
die "Unknown type $type"; |
22 | 23 |
} |
SL/DB/OrderItem.pm | ||
---|---|---|
2 | 2 |
|
3 | 3 |
use strict; |
4 | 4 |
|
5 |
use List::Util qw(sum); |
|
6 |
use SL::AM; |
|
7 |
|
|
5 | 8 |
use SL::DB::MetaSetup::OrderItem; |
6 | 9 |
use SL::DB::Helper::CustomVariables ( |
7 | 10 |
sub_module => 'orderitems', |
... | ... | |
44 | 47 |
return $self->origprice > $self->part->sellprice; |
45 | 48 |
} |
46 | 49 |
|
50 |
sub shipped_qty { |
|
51 |
my ($self) = @_; |
|
52 |
|
|
53 |
my $d_orders = $self->order->linked_records(direction => 'to', to => 'SL::DB::DeliveryOrder'); |
|
54 |
my @doi = grep { $_->parts_id == $self->parts_id } map { $_->orderitems } @$d_orders; |
|
55 |
|
|
56 |
return sum(map { AM->convert_unit($_->unit => $self->unit) * $_->qty } @doi); |
|
57 |
} |
|
58 |
|
|
47 | 59 |
package SL::DB::Manager::OrderItem; |
48 | 60 |
|
49 | 61 |
use SL::DB::Helper::Paginated; |
... | ... | |
57 | 69 |
ordnumber => [ 'order.ordnumber' ], |
58 | 70 |
customer => [ 'lower(customer.name)', ], |
59 | 71 |
position => [ 'trans_id', 'runningnumber' ], |
60 |
transdate => [ 'transdate', 'lower(order.reqdate::text)' ], |
|
72 |
reqdate => [ 'COALESCE(orderitems.reqdate, order.transdate)' ], |
|
73 |
orddate => [ 'order.orddate' ], |
|
74 |
sellprice => [ 'sellprice' ], |
|
75 |
discount => [ 'discount' ], |
|
61 | 76 |
}, |
62 | 77 |
default => [ 'position', 1 ], |
63 | 78 |
nulls => { } |
templates/webpages/oe/sales_price_information.html | ||
---|---|---|
1 |
[% USE HTML %] |
|
2 |
[% USE LxERP %] |
|
3 |
[% USE T8 %] |
|
4 |
[%- IF !TABDIALOG %] |
|
5 |
<body> |
|
6 |
|
|
7 |
<p><div class="listtop">[% 'Price information' | $T8 %]</div></p> |
|
8 |
|
|
9 |
<p> |
|
10 |
<input type="button" class="submit" onclick="window.close()" value="[% 'Close window' | $T8 %]"> |
|
11 |
</p> |
|
12 |
|
|
13 |
<p> |
|
14 |
<table> |
|
15 |
<tr> |
|
16 |
<td>[% 'Part Number' | $T8 %]:</td> |
|
17 |
<td>[% HTML.escape(part_info.partnumber) %]</td> |
|
18 |
</tr> |
|
19 |
|
|
20 |
<tr> |
|
21 |
<td>[% 'Description' | $T8 %]:</td> |
|
22 |
<td>[% HTML.escape(part_info.description) %]</td> |
|
23 |
</tr> |
|
24 |
|
|
25 |
[%- UNLESS part_info.type == 'service' %] |
|
26 |
<tr> |
|
27 |
<td>[% 'Stocked' | $T8 %]:</td> |
|
28 |
<td>[% HTML.escape(LxERP.format_amount_units(stocked, part_info.unit, part_info.unit)) %]</td> |
|
29 |
</tr> |
|
30 |
[%- END %] |
|
31 |
</table> |
|
32 |
</p> |
|
33 |
|
|
34 |
[%- END %] |
|
35 |
|
|
36 |
<p> |
|
37 |
<table> |
|
38 |
[%- SET custom_texts = { |
|
39 |
sales_order => { |
|
40 |
head => LxERP.t8('Sales Orders'), |
|
41 |
empty => LxERP.t8('This part has not been used in a sales order yet.'), |
|
42 |
date => LxERP.t8('Order Date'), |
|
43 |
number => LxERP.t8('Order Number'), |
|
44 |
vc => LxERP.t8('Customer'), |
|
45 |
}, |
|
46 |
sales_quotation => { |
|
47 |
head => LxERP.t8('Quotations'), |
|
48 |
empty => LxERP.t8('This part has not been used in a quotation yet.'), |
|
49 |
date => LxERP.t8('Quotation Date'), |
|
50 |
number => LxERP.t8('Quotation Number'), |
|
51 |
vc => LxERP.t8('Customer'), |
|
52 |
}, |
|
53 |
purchase_order => { |
|
54 |
head => LxERP.t8('Purchase Orders'), |
|
55 |
empty => LxERP.t8('This part has not been used in a purchase order yet.'), |
|
56 |
date => LxERP.t8('Order Date'), |
|
57 |
number => LxERP.t8('Order Number'), |
|
58 |
vc => LxERP.t8('Vendor'), |
|
59 |
}, |
|
60 |
request_quotation => { |
|
61 |
head => LxERP.t8('RFQs'), |
|
62 |
empty => LxERP.t8('This part has not been used in a request quotation yet.'), |
|
63 |
date => LxERP.t8('Quotation Date'), |
|
64 |
number => LxERP.t8('Quotation Number'), |
|
65 |
vc => LxERP.t8('Vendor'), |
|
66 |
}, |
|
67 |
} |
|
68 |
%] |
|
69 |
[%- FOREACH type = ['sales_order', 'sales_quotation', 'purchase_order', 'request_quotation'] %] |
|
70 |
|
|
71 |
<tr> |
|
72 |
<th class="listtop" colspan="8">[% custom_texts.$type.head %]</th> |
|
73 |
</tr> |
|
74 |
|
|
75 |
[%- IF !PRICE_INFO.$type.size %] |
|
76 |
<tr> |
|
77 |
<td colspan="7">[% custom_texts.$type.empty %]</td> |
|
78 |
</tr> |
|
79 |
|
|
80 |
[%- ELSE %] |
|
81 |
|
|
82 |
<tr> |
|
83 |
<th class="listheading">[% custom_texts.$type.date %]</th> |
|
84 |
<th class="listheading">[% custom_texts.$type.number %]</th> |
|
85 |
<th class="listheading">[% custom_texts.$type.vc %]</th> |
|
86 |
<th class="listheading">[% 'Delivered' | $T8 %]</th> |
|
87 |
<th class="listheading" align="right">[% 'Quantity' | $T8 %]</th> |
|
88 |
<th class="listheading" align="right">[% 'Unit price' | $T8 %]</th> |
|
89 |
<th class="listheading" align="right">[% 'Discount' | $T8 %]</th> |
|
90 |
<th class="listheading" align="right">[% 'Line total' | $T8 %]</th> |
|
91 |
</tr> |
|
92 |
|
|
93 |
[%- FOREACH row = PRICE_INFO.$type %] |
|
94 |
<tr class="listrow[% loop.count % 2 %]"> |
|
95 |
<td>[% HTML.escape(row.date) %]</td> |
|
96 |
<td><a href="oe.pl?action=edit&type=[% type | html %]&id=[% row.id | html %]">[% HTML.escape(row.number) %]</a></td> |
|
97 |
<td>[% HTML.escape(row.vc) %]</td> |
|
98 |
<td align="right">[% HTML.escape(LxERP.format_amount(row.ship)) %] [% HTML.escape(row.unit) %]</td> |
|
99 |
<td align="right">[% HTML.escape(LxERP.format_amount(row.qty)) %] [% HTML.escape(row.unit) %]</td> |
|
100 |
<td align="right">[% HTML.escape(LxERP.format_amount(row.sellprice, 2)) %]</td> |
|
101 |
<td align="right">[% HTML.escape(LxERP.format_amount(row.discount * 100)) %]</td> |
|
102 |
<td align="right">[% HTML.escape(LxERP.format_amount(row.linetotal, 2)) %]</td> |
|
103 |
</tr> |
|
104 |
[%- END %] |
|
105 |
[%- END %] |
|
106 |
[%- END %] |
|
107 |
</table> |
|
108 |
</p> |
|
109 |
|
|
110 |
[%- IF !TABDIALOG %] |
|
111 |
</body> |
|
112 |
</html> |
|
113 |
[%- END %] |
templates/webpages/price_information/report_bottom.html | ||
---|---|---|
1 |
<p align=right>[% PROCESS 'common/paginate.html' pages=SELF.pages, base_url=SELF.self_url %]</p> |
Auch abrufbar als: Unified diff
sellprice information test commit