]> wagnertech.de Git - mfinanz.git/blob - SL/Controller/PartsPriceUpdate.pm
kivitendo 3.9.2-0.2
[mfinanz.git] / SL / Controller / PartsPriceUpdate.pm
1 package SL::Controller::PartsPriceUpdate;
2
3 use strict;
4 use parent qw(SL::Controller::Base);
5
6 use SL::DBUtils qw(prepare_query selectfirst_array_query prepare_query do_statement do_query);
7 use SL::JSON;
8 use SL::Helper::Flash qw(flash);
9 use SL::DB;
10 use SL::DB::Part;
11 use SL::DB::Pricegroup;
12 use SL::Locale::String qw(t8);
13
14 use Rose::Object::MakeMethods::Generic (
15   'scalar --get_set_init' => [ qw(pricegroups pricegroups_by_id filter) ],
16 );
17
18 __PACKAGE__->run_before('check_rights');
19
20
21 sub action_search_update_prices {
22   my ($self) = @_;
23
24   $self->setup_search_update_prices_action_bar;
25   $self->render('ic/search_update_prices',
26     title => t8('Update Prices'),
27   );
28 }
29
30 sub action_confirm_price_update {
31   my ($self) = @_;
32
33   my @errors;
34   my $found;
35
36   for my $key (keys %{ $self->filter->{prices} || {} }) {
37     my $row = $self->filter->{prices}{$key};
38
39     next if $row->{price_as_number} eq '';
40
41     my $type   = $row->{type};
42     my $value  = $::form->parse_amount(\%::myconfig, $row->{price_as_number});
43     my $name   = $key =~ /^\d+$/      ? $self->pricegroups_by_id->{$key}->pricegroup
44                : $key eq 'sellprice'  ? t8('Sell Price')
45                : $key eq 'listprice'  ? t8('List Price')
46                :                        '';
47
48     if (0 > $value && ($type eq 'percent')) {
49       push @errors, t8('You cannot adjust the price for pricegroup "#1" by a negative percentage.', $name);
50     } elsif (!$value) {
51       push @errors, t8('No valid number entered for pricegroup "#1".', $name);
52     } elsif (0 < $value) {
53       $found = 1;
54     }
55   }
56
57   push @errors, t8('No prices will be updated because no prices have been entered.') if !$found;
58
59   my $num_matches = $self->get_num_matches_for_priceupdate();
60
61   if (@errors) {
62     flash('error', $_) for @errors;
63     return $self->action_search_update_prices;
64   } else {
65
66     my $key = $::auth->create_unique_session_value(SL::JSON::to_json($self->filter));
67
68     $self->setup_confirm_price_update_action_bar;
69     $self->render('ic/confirm_price_update',
70       num_matches => $num_matches,
71       filter_key  => $key,
72     );
73   }
74 }
75
76 sub action_update_prices {
77   my ($self) = @_;
78
79   my $num_updated = $self->do_update_prices;
80
81   if ($num_updated) {
82     $::form->redirect(t8('#1 prices were updated.', $num_updated));
83   } else {
84     $::form->error(t8('Could not update prices!'));
85   }
86 }
87
88 sub _create_filter_for_priceupdate {
89   my ($self) = @_;
90   my $filter = $self->filter;
91
92   my @where_values;
93   my $where = '1 = 1';
94
95   for my $item (qw(partnumber drawing microfiche pg.partsgroup description serialnumber)) {
96     my $column = $item;
97     $column =~ s/.*\.//;
98     next unless $filter->{$column};
99
100     $where .= qq| AND $item ILIKE ?|;
101     push @where_values, "%$filter->{$column}%";
102   }
103
104   # items which were never bought, sold or on an order
105   if ($filter->{itemstatus} eq 'orphaned') {
106     $where .=
107       qq| AND (p.onhand = 0)
108           AND p.id NOT IN
109             (
110               SELECT DISTINCT parts_id FROM invoice
111               UNION
112               SELECT DISTINCT parts_id FROM assembly
113               UNION
114               SELECT DISTINCT parts_id FROM orderitems
115               UNION
116               SELECT DISTINCT parts_id FROM delivery_order_items
117             )|;
118
119   } elsif ($filter->{itemstatus} eq 'active') {
120     $where .= qq| AND p.obsolete = '0'|;
121
122   } elsif ($filter->{itemstatus} eq 'obsolete') {
123     $where .= qq| AND p.obsolete = '1'|;
124
125   } elsif ($filter->{itemstatus} eq 'onhand') {
126     $where .= qq| AND p.onhand > 0|;
127
128   } elsif ($filter->{itemstatus} eq 'short') {
129     $where .= qq| AND p.onhand < p.rop|;
130
131   }
132
133   if ($filter->{make}) {
134     $where .= qq| AND p.id IN (SELECT DISTINCT parts_id FROM makemodel WHERE make = ?) |;
135     push @where_values, $filter->{make};
136   }
137
138   if ($filter->{model}) {
139     $where .= qq| AND p.id IN (SELECT DISTINCT parts_id FROM makemodel WHERE model ILIKE ?) |;
140     push @where_values, "%$filter->{model}%";
141   }
142
143   return ($where, @where_values);
144 }
145
146 sub get_num_matches_for_priceupdate {
147   my ($self)   = @_;
148   my $filter   = $self->filter;
149   my $dbh      = SL::DB->client->dbh;
150   my ($where, @where_values) = $self->_create_filter_for_priceupdate;
151
152   my $num_updated = 0;
153   my $query;
154
155   for my $column (qw(sellprice listprice)) {
156     next if $filter->{prices}{$column}{price_as_number} eq "";
157
158     $query =
159       qq|SELECT COUNT(*)
160          FROM parts
161          WHERE id IN
162            (SELECT p.id
163             FROM parts p
164             LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
165             WHERE $where)|;
166     my ($result)  = selectfirst_array_query($::form, $dbh, $query, @where_values);
167     $num_updated += $result if (0 <= $result);
168   }
169
170   my @ids = grep { $filter->{prices}{$_}{price_as_number} } map { $_->id } @{ $self->pricegroups };
171   if (@ids) {
172     $query =
173       qq|SELECT COUNT(*)
174          FROM prices
175          WHERE parts_id IN
176            (SELECT p.id
177             FROM parts p
178             LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
179             WHERE $where)
180          AND pricegroup_id IN (@{[ join ',', ('?')x@ids ]})|;
181
182     my ($result)  = selectfirst_array_query($::form, $dbh, $query, @where_values, @ids);
183     $num_updated += $result if (0 <= $result);
184   }
185
186   return $num_updated;
187 }
188
189 sub do_update_prices {
190   SL::DB->client->with_transaction(\&_update_prices, $_[0]);
191 }
192
193 sub _update_prices {
194   my ($self) = @_;
195   my $filter_json = $::auth->get_session_value($::form->{filter_key});
196   my $filter = SL::JSON::from_json($filter_json);
197   $self->filter($filter);
198   die "missing filter" unless $filter;
199
200   my ($where, @where_values) = $self->_create_filter_for_priceupdate;
201   my $num_updated = 0;
202
203   # connect to database
204   my $dbh = SL::DB->client->dbh;
205
206   for my $column (qw(sellprice listprice)) {
207     my $row = $filter->{prices}{$column};
208     next if ($row->{price_as_number} eq "");
209
210     my $value = $::form->parse_amount(\%::myconfig, $row->{price_as_number});
211     my $operator = '+';
212
213     if ($row->{type} eq "percent") {
214       $value = ($value / 100) + 1;
215       $operator = '*';
216     }
217
218     my $query =
219       qq|UPDATE parts SET $column = $column $operator ?
220          WHERE id IN
221            (SELECT p.id
222             FROM parts p
223             LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
224             WHERE $where)|;
225     my $result    = do_query($::form, $dbh, $query, $value, @where_values);
226     $num_updated += $result if 0 <= $result;
227   }
228
229   my $q_add =
230     qq|UPDATE prices SET price = price + ?
231        WHERE parts_id IN
232          (SELECT p.id
233           FROM parts p
234           LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
235           WHERE $where) AND (pricegroup_id = ?)|;
236   my $sth_add = prepare_query($::form, $dbh, $q_add);
237
238   my $q_multiply =
239     qq|UPDATE prices SET price = price * ?
240        WHERE parts_id IN
241          (SELECT p.id
242           FROM parts p
243           LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
244           WHERE $where) AND (pricegroup_id = ?)|;
245   my $sth_multiply = prepare_query($::form, $dbh, $q_multiply);
246
247   for my $pg (@{ $self->pricegroups }) {
248     my $row = $filter->{prices}{$pg->id};
249     next if $row->{price_as_number} eq "";
250
251     my $value = $::form->parse_amount(\%::myconfig, $row->{price_as_number});
252     my $result;
253
254     if ($row->{type} eq "percent") {
255       $result = do_statement($::form, $sth_multiply, $q_multiply, ($value / 100) + 1, @where_values, $pg->id);
256     } else {
257       $result = do_statement($::form, $sth_add, $q_add, $value, @where_values, $pg->id);
258     }
259
260     $num_updated += $result if (0 <= $result);
261   }
262
263   $sth_add->finish;
264   $sth_multiply->finish;
265
266   1;
267 }
268
269 sub init_pricegroups {
270   SL::DB::Manager::Pricegroup->get_all_sorted(query => [
271     obsolete => 0,
272   ]);
273 }
274
275 sub init_pricegroups_by_id {
276   +{ map { $_->id => $_ } @{ $_[0]->pricegroups } }
277 }
278
279 sub check_rights {
280   $::auth->assert('part_service_assembly_edit & part_service_assembly_edit_prices');
281 }
282
283 sub init_filter {
284   $::form->{filter} || {};
285 }
286
287 sub setup_search_update_prices_action_bar {
288   my ($self, %params) = @_;
289
290   for my $bar ($::request->layout->get('actionbar')) {
291     $bar->add(
292       action => [
293         t8('Continue'),
294         submit    => [ '#form', { action => 'PartsPriceUpdate/confirm_price_update' } ],
295         accesskey => 'enter',
296       ],
297     );
298   }
299 }
300
301 sub setup_confirm_price_update_action_bar {
302   my ($self, %params) = @_;
303
304   for my $bar ($::request->layout->get('actionbar')) {
305     $bar->add(
306       action => [
307         t8('Continue'),
308         submit    => [ '#form', { action => 'PartsPriceUpdate/update_prices' } ],
309         accesskey => 'enter',
310       ],
311
312       action => [
313         t8('Back'),
314         call => [ 'kivi.history_back' ],
315       ],
316     );
317   }
318 }
319
320 1;