1 package SL::Controller::PartsPriceUpdate;
4 use parent qw(SL::Controller::Base);
6 use SL::DBUtils qw(prepare_query selectfirst_array_query prepare_query do_statement do_query);
8 use SL::Helper::Flash qw(flash);
11 use SL::DB::Pricegroup;
12 use SL::Locale::String qw(t8);
14 use Rose::Object::MakeMethods::Generic (
15 'scalar --get_set_init' => [ qw(pricegroups pricegroups_by_id filter) ],
18 __PACKAGE__->run_before('check_rights');
21 sub action_search_update_prices {
24 $self->setup_search_update_prices_action_bar;
25 $self->render('ic/search_update_prices',
26 title => t8('Update Prices'),
30 sub action_confirm_price_update {
36 for my $key (keys %{ $self->filter->{prices} || {} }) {
37 my $row = $self->filter->{prices}{$key};
39 next if $row->{price_as_number} eq '';
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')
48 if (0 > $value && ($type eq 'percent')) {
49 push @errors, t8('You cannot adjust the price for pricegroup "#1" by a negative percentage.', $name);
51 push @errors, t8('No valid number entered for pricegroup "#1".', $name);
52 } elsif (0 < $value) {
57 push @errors, t8('No prices will be updated because no prices have been entered.') if !$found;
59 my $num_matches = $self->get_num_matches_for_priceupdate();
62 flash('error', $_) for @errors;
63 return $self->action_search_update_prices;
66 my $key = $::auth->create_unique_session_value(SL::JSON::to_json($self->filter));
68 $self->setup_confirm_price_update_action_bar;
69 $self->render('ic/confirm_price_update',
70 num_matches => $num_matches,
76 sub action_update_prices {
79 my $num_updated = $self->do_update_prices;
82 $::form->redirect(t8('#1 prices were updated.', $num_updated));
84 $::form->error(t8('Could not update prices!'));
88 sub _create_filter_for_priceupdate {
90 my $filter = $self->filter;
95 for my $item (qw(partnumber drawing microfiche make model pg.partsgroup description serialnumber)) {
98 next unless $filter->{$column};
100 $where .= qq| AND $item ILIKE ?|;
101 push @where_values, "%$filter->{$column}%";
104 # items which were never bought, sold or on an order
105 if ($filter->{itemstatus} eq 'orphaned') {
107 qq| AND (p.onhand = 0)
110 SELECT DISTINCT parts_id FROM invoice
112 SELECT DISTINCT parts_id FROM assembly
114 SELECT DISTINCT parts_id FROM orderitems
116 SELECT DISTINCT parts_id FROM delivery_order_items
119 } elsif ($filter->{itemstatus} eq 'active') {
120 $where .= qq| AND p.obsolete = '0'|;
122 } elsif ($filter->{itemstatus} eq 'obsolete') {
123 $where .= qq| AND p.obsolete = '1'|;
125 } elsif ($filter->{itemstatus} eq 'onhand') {
126 $where .= qq| AND p.onhand > 0|;
128 } elsif ($filter->{itemstatus} eq 'short') {
129 $where .= qq| AND p.onhand < p.rop|;
133 for my $column (qw(make model)) {
134 next unless ($filter->{$column});
135 $where .= qq| AND p.id IN (SELECT DISTINCT parts_id FROM makemodel WHERE $column ILIKE ?|;
136 push @where_values, "%$filter->{$column}%";
139 return ($where, @where_values);
142 sub get_num_matches_for_priceupdate {
144 my $filter = $self->filter;
145 my $dbh = SL::DB->client->dbh;
146 my ($where, @where_values) = $self->_create_filter_for_priceupdate;
151 for my $column (qw(sellprice listprice)) {
152 next if $filter->{prices}{$column}{price_as_number} eq "";
160 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
162 my ($result) = selectfirst_array_query($::form, $dbh, $query, @where_values);
163 $num_updated += $result if (0 <= $result);
166 my @ids = grep { $filter->{prices}{$_}{price_as_number} } map { $_->id } @{ $self->pricegroups };
174 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
176 AND pricegroup_id IN (@{[ join ',', ('?')x@ids ]})|;
178 my ($result) = selectfirst_array_query($::form, $dbh, $query, @where_values, @ids);
179 $num_updated += $result if (0 <= $result);
185 sub do_update_prices {
186 SL::DB->client->with_transaction(\&_update_prices, $_[0]);
191 my $filter_json = $::auth->get_session_value($::form->{filter_key});
192 my $filter = SL::JSON::from_json($filter_json);
193 $self->filter($filter);
194 die "missing filter" unless $filter;
196 my ($where, @where_values) = $self->_create_filter_for_priceupdate;
199 # connect to database
200 my $dbh = SL::DB->client->dbh;
202 for my $column (qw(sellprice listprice)) {
203 my $row = $filter->{prices}{$column};
204 next if ($row->{price_as_number} eq "");
206 my $value = $::form->parse_amount(\%::myconfig, $row->{price_as_number});
209 if ($row->{type} eq "percent") {
210 $value = ($value / 100) + 1;
215 qq|UPDATE parts SET $column = $column $operator ?
219 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
221 my $result = do_query($::form, $dbh, $query, $value, @where_values);
222 $num_updated += $result if 0 <= $result;
226 qq|UPDATE prices SET price = price + ?
230 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
231 WHERE $where) AND (pricegroup_id = ?)|;
232 my $sth_add = prepare_query($::form, $dbh, $q_add);
235 qq|UPDATE prices SET price = price * ?
239 LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
240 WHERE $where) AND (pricegroup_id = ?)|;
241 my $sth_multiply = prepare_query($::form, $dbh, $q_multiply);
243 for my $pg (@{ $self->pricegroups }) {
244 my $row = $filter->{prices}{$pg->id};
245 next if $row->{price_as_number} eq "";
247 my $value = $::form->parse_amount(\%::myconfig, $row->{price_as_number});
250 if ($row->{type} eq "percent") {
251 $result = do_statement($::form, $sth_multiply, $q_multiply, ($value / 100) + 1, @where_values, $pg->id);
253 $result = do_statement($::form, $sth_add, $q_add, $value, @where_values, $pg->id);
256 $num_updated += $result if (0 <= $result);
260 $sth_multiply->finish;
265 sub init_pricegroups {
266 SL::DB::Manager::Pricegroup->get_all_sorted(query => [
271 sub init_pricegroups_by_id {
272 +{ map { $_->id => $_ } @{ $_[0]->pricegroups } }
276 $::auth->assert('part_service_assembly_edit');
280 $::form->{filter} || {};
283 sub setup_search_update_prices_action_bar {
284 my ($self, %params) = @_;
286 for my $bar ($::request->layout->get('actionbar')) {
290 submit => [ '#form', { action => 'PartsPriceUpdate/confirm_price_update' } ],
291 accesskey => 'enter',
297 sub setup_confirm_price_update_action_bar {
298 my ($self, %params) = @_;
300 for my $bar ($::request->layout->get('actionbar')) {
304 submit => [ '#form', { action => 'PartsPriceUpdate/update_prices' } ],
305 accesskey => 'enter',
310 call => [ 'kivi.history_back' ],