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' ],