]> wagnertech.de Git - kivitendo-erp.git/commitdiff
Merge branch 'master' of github.com:kivitendo/kivitendo-erp
authorSven Schöling <s.schoeling@linet-services.de>
Fri, 12 Jul 2013 13:14:47 +0000 (15:14 +0200)
committerSven Schöling <s.schoeling@linet-services.de>
Fri, 12 Jul 2013 13:14:47 +0000 (15:14 +0200)
16 files changed:
SL/Controller/Helper/Filtered.pm
SL/Controller/Helper/Paginated.pm
SL/Controller/Helper/ParseFilter.pm
SL/Controller/Part.pm
SL/DB/Helper/PriceTaxCalculator.pm
SL/DB/Manager/Part.pm
SL/DB/Manager/Unit.pm
SL/DB/PaymentTerm.pm
SL/DBUpgrade2/Base.pm
SL/DO.pm
SL/Form.pm
SL/OE.pm
SL/Presenter/Part.pm
js/autocomplete_part.js
js/common.js
sql/Pg-upgrade2/oe_do_delete_via_trigger.pl [new file with mode: 0644]

index d248bf6f3547d9184f0d5058f2ac8fda37d95004..c5b876f414d1f9736a764cbf52ef505529416d33 100644 (file)
@@ -12,19 +12,19 @@ use constant PRIV => '__filteredhelper_priv';
 my %controller_filter_spec;
 
 sub make_filtered {
-  my ($class, %specs)       = @_;
+  my ($class, %specs)             = @_;
 
-  $specs{MODEL}           //=  $class->controller_name;
-  $specs{MODEL}             =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
-  $specs{FORM_PARAMS}     //= 'filter';
-  $specs{LAUNDER_TO}        = '__INPLACE__' unless exists $specs{LAUNDER_TO};
-  $specs{ONLY}            //= [];
-  $specs{ONLY}              = [ $specs{ONLY} ] if !ref $specs{ONLY};
-  $specs{ONLY_MAP}          = @{ $specs{ONLY} } ? { map { ($_ => 1) } @{ $specs{ONLY} } } : { '__ALL__' => 1 };
+  $specs{MODEL}                 //=  $class->controller_name;
+  $specs{MODEL}                   =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
+  $specs{FORM_PARAMS}           //= 'filter';
+  $specs{LAUNDER_TO}              = '__INPLACE__' unless exists $specs{LAUNDER_TO};
+  $specs{ONLY}                  //= [];
+  $specs{ONLY}                    = [ $specs{ONLY} ] if !ref $specs{ONLY};
+  $specs{ONLY_MAP}                = @{ $specs{ONLY} } ? { map { ($_ => 1) } @{ $specs{ONLY} } } : { '__ALL__' => 1 };
 
   $controller_filter_spec{$class} = \%specs;
 
-  my %hook_params           = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
+  my %hook_params                 = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
   $class->run_before('_save_current_filter_params', %hook_params);
 
   SL::Controller::Helper::GetModels::register_get_models_handlers(
@@ -76,15 +76,15 @@ sub _make_current_filter_params {
 
   $calculated_params{query} = [
     @{ $calculated_params{query} || [] },
-    @{ $filter_args{query} || [] },
-    @{ $params{query} || [] },
+    @{ $filter_args{      query} || [] },
+    @{ $params{           query} || [] },
   ];
 
   $calculated_params{with_objects} = [
     uniq
     @{ $calculated_params{with_objects} || [] },
-    @{ $filter_args{with_objects} || [] },
-    @{ $params{with_objects} || [] },
+    @{ $filter_args{      with_objects} || [] },
+    @{ $params{           with_objects} || [] },
   ];
 
   if ($laundered) {
@@ -114,11 +114,11 @@ sub disable_filtering {
 sub _get_filter_args {
   my ($self, $spec) = @_;
 
-  $spec ||= $self->get_filter_spec;
+  $spec           ||= $self->get_filter_spec;
 
-  my %filter_args       = ref($spec->{FILTER_ARGS}) eq 'CODE' ? %{ $spec->{FILTER_ARGS}->($self) }
-                        :     $spec->{FILTER_ARGS}            ? do { my $sub = $spec->{FILTER_ARGS}; %{ $self->$sub() } }
-                        :                                       ();
+  my %filter_args   = ref($spec->{FILTER_ARGS}) eq 'CODE' ? %{ $spec->{FILTER_ARGS}->($self) }
+                    :     $spec->{FILTER_ARGS}            ? do { my $sub = $spec->{FILTER_ARGS}; %{ $self->$sub() } }
+                    :                                       ();
 }
 
 sub _save_current_filter_params {
@@ -137,9 +137,9 @@ sub _callback_handler_for_filtered {
   my $priv            = _priv($self);
 
   if (_is_enabled($self) && $priv->{filter}) {
-    my $filter_spec                             = $self->get_filter_spec;
+    my $filter_spec = $self->get_filter_spec;
     my ($flattened) = SL::Controller::Helper::ParseFilter::flatten($priv->{filter}, undef, $filter_spec->{FORM_PARAMS});
-    %params = (%params, @$flattened);
+    %params         = (%params, @$flattened);
   }
 
   # $::lxdebug->dump(0, "CB handler for filtered; params after flatten:", \%params);
@@ -172,7 +172,6 @@ sub _is_enabled {
   return !_priv($self)->{disabled} && ($self->get_filter_spec->{ONLY_MAP}->{$self->action_name} || $self->get_filter_spec->{ONLY_MAP}->{'__ALL__'});
 }
 
-
 1;
 
 __END__
index 25c4efa09ead74929f3a9ca63d2d4e13fbe62d44..0db285f1e0106ee04eaf8529a17e1fef3c25c7f9 100644 (file)
@@ -12,20 +12,20 @@ use List::Util qw(min);
 my %controller_paginate_spec;
 
 sub make_paginated {
-  my ($class, %specs)       = @_;
+  my ($class, %specs)               = @_;
 
-  $specs{MODEL}           ||=  $class->controller_name;
-  $specs{MODEL}             =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
-  $specs{PER_PAGE}        ||= "SL::DB::Manager::$specs{MODEL}"->default_objects_per_page;
-  $specs{FORM_PARAMS}     ||= [ qw(page per_page) ];
-  $specs{PAGINATE_ARGS}   ||= '__FILTER__';
-  $specs{ONLY}            ||= [];
-  $specs{ONLY}              = [ $specs{ONLY} ] if !ref $specs{ONLY};
-  $specs{ONLY_MAP}          = @{ $specs{ONLY} } ? { map { ($_ => 1) } @{ $specs{ONLY} } } : { '__ALL__' => 1 };
+  $specs{MODEL}                   ||=  $class->controller_name;
+  $specs{MODEL}                     =~ s{ ^ SL::DB:: (?: .* :: )? }{}x;
+  $specs{PER_PAGE}                ||= "SL::DB::Manager::$specs{MODEL}"->default_objects_per_page;
+  $specs{FORM_PARAMS}             ||= [ qw(page per_page) ];
+  $specs{PAGINATE_ARGS}           ||= '__FILTER__';
+  $specs{ONLY}                    ||= [];
+  $specs{ONLY}                      = [ $specs{ONLY} ] if !ref $specs{ONLY};
+  $specs{ONLY_MAP}                  = @{ $specs{ONLY} } ? { map { ($_ => 1) } @{ $specs{ONLY} } } : { '__ALL__' => 1 };
 
   $controller_paginate_spec{$class} = \%specs;
 
-  my %hook_params           = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
+  my %hook_params                   = @{ $specs{ONLY} } ? ( only => $specs{ONLY} ) : ();
   $class->run_before('_save_current_paginate_params', %hook_params);
 
   SL::Controller::Helper::GetModels::register_get_models_handlers(
index 8b26e88b6eaaf67e0a5fb48bcaf52457aa0a5c78..1d0515cc86533e13616f2265ddb2c223f06fb822 100644 (file)
@@ -80,7 +80,7 @@ sub flatten {
     next if !defined $value || $value eq ''; # 0 is fine
     if ('HASH' eq ref $value) {
       my ($query, $more_objects) = flatten($value, _prefix($prefix, $key));
-      push @result,        @$query if $query;
+      push @result, @$query        if  $query;
       _add_uniq($with_objects, $_) for _prefix($prefix, $key), @$more_objects;
     } else {
       push @result, _prefix($prefix, $key) => $value;
index 9b4744e9e6bebdb8cf8ae2fcc6e53cf2a175dfde..38b3b55027507ea7795f2b70a011960b86ee08a2 100644 (file)
@@ -21,20 +21,20 @@ use Rose::Object::MakeMethods::Generic (
 __PACKAGE__->run_before(sub { $::auth->assert('part_service_assembly_edit') });
 
 __PACKAGE__->make_filtered(
-  ONLY          => [ qw(part_picker_search part_picker_result ajax_autocomplete) ],
-  LAUNDER_TO    => 'filter',
+  ONLY        => [ qw(part_picker_search part_picker_result ajax_autocomplete) ],
+  LAUNDER_TO  => 'filter',
 );
 __PACKAGE__->make_paginated(
-  ONLY          => [ qw(part_picker_search part_picker_result ajax_autocomplete) ],
+  ONLY        => [ qw(part_picker_search part_picker_result ajax_autocomplete) ],
 );
 
 __PACKAGE__->make_sorted(
-  ONLY              => [ qw(part_picker_search part_picker_result ajax_autocomplete) ],
+  ONLY        => [ qw(part_picker_search part_picker_result ajax_autocomplete) ],
 
-  DEFAULT_BY        => 'partnumber',
-  DEFAULT_DIR       => 1,
+  DEFAULT_BY  => 'partnumber',
+  DEFAULT_DIR => 1,
 
-  partnumber        => t8('Partnumber'),
+  partnumber  => t8('Partnumber'),
 );
 
 sub action_ajax_autocomplete {
@@ -92,7 +92,7 @@ sub action_part_picker_result {
 }
 
 sub init_parts {
-  $_[0]->get_models;
+  $_[0]->get_models(with_objects => [ qw(unit_obj) ]);
 }
 
 1;
index e4a91807ba60adeccc176eb5fd05a001033b6b67..af5664694f424f0ad2a9411dc2c5fb4f9d09023a 100644 (file)
@@ -90,13 +90,14 @@ sub _calculate_item {
     $item->marge_percent(0);
 
   } else {
-    my $lastcost = ! ($item->lastcost * 1) ? ($item->part->lastcost || 0) : $item->lastcost;
+    my $lastcost       = ! ($item->lastcost * 1) ? ($item->part->lastcost || 0) : $item->lastcost;
+    my $linetotal_cost = _round($lastcost * $item->qty / $item->marge_price_factor, 2);
 
-    $item->marge_total(  $linetotal - $lastcost / $item->marge_price_factor);
+    $item->marge_total(  $linetotal - $linetotal_cost);
     $item->marge_percent($item->marge_total * 100 / $linetotal);
 
     $self->marge_total(  $self->marge_total + $item->marge_total);
-    $data->{lastcost_total} += $lastcost;
+    $data->{lastcost_total} += $linetotal_cost;
   }
 
   my $taxkey     = $item->part->get_taxkey(date => $self->transdate, is_sales => $data->{is_sales}, taxzone => $self->taxzone_id);
index 159f59998d96064de4e8942ffbe5f22ac43ddad1..0b751bd34b58bd6af513252f8dfc9cb28ab5f20f 100644 (file)
@@ -35,29 +35,28 @@ sub type_filter {
 
   # this is to make selection like type => { part => 1, service => 1 } work
   if ('HASH' eq ref $type) {
-    $type = grep { $type->{$_} } keys %$type;
+    $type = [ grep { $type->{$_} } keys %$type ];
   }
 
-  my @types = listify($type);
+  my @types = grep { $_ } listify($type);
   my @filter;
 
   for my $type (@types) {
     if ($type =~ m/^part/) {
-      push @filter, (and => [ or                    => [ $prefix . assembly => 0, $prefix . assembly => undef ],
-                       "!${prefix}inventory_accno_id" => 0,
-                       "!${prefix}inventory_accno_id" => undef,
+      push @filter, (and => [ or                             => [ $prefix . assembly => 0, $prefix . assembly => undef ],
+                              "!${prefix}inventory_accno_id" => 0,
+                              "!${prefix}inventory_accno_id" => undef,
                      ]);
     } elsif ($type =~ m/^service/) {
       push @filter, (and => [ or => [ $prefix . assembly           => 0, $prefix . assembly           => undef ],
-                       or => [ $prefix . inventory_accno_id => 0, $prefix . inventory_accno_id => undef ],
+                              or => [ $prefix . inventory_accno_id => 0, $prefix . inventory_accno_id => undef ],
                      ]);
     } elsif ($type =~ m/^assembl/) {
       push @filter, ($prefix . assembly => 1);
     }
   }
 
-  return @filter > 2 ? (or => \@filter) :
-         @filter     ? @filter          : ();
+  return @filter > 2 ? (or => \@filter) : @filter;
 }
 
 sub get_ordered_qty {
index 8b3c138a8852d08aa8ba19bd970c6d3d651d1c39..f081af49ee8ba6d4aa1bcfa86c6ad33b4abc1b60 100644 (file)
@@ -6,10 +6,17 @@ use SL::DB::Helper::Manager;
 use base qw(SL::DB::Helper::Manager);
 
 use SL::DB::Helper::Sorted;
+use SL::DB::Helper::Filtered;
 
 sub object_class { 'SL::DB::Unit' }
 
 __PACKAGE__->make_manager_methods;
+__PACKAGE__->add_filter_specs(
+  convertible_to => sub {
+    my ($key, $value, $prefix) = @_;
+    return __PACKAGE__->convertible_to_filter($key, $value, $prefix);
+  },
+);
 
 sub _sort_spec {
   return ( default => [ 'sortkey', 1 ],
@@ -18,4 +25,20 @@ sub _sort_spec {
                       });
 }
 
+sub convertible_to_filter {
+  my ($class, $key, $unit_name, $prefix) = @_;
+
+  return () unless $unit_name;
+
+  $prefix //= '';
+
+  my $unit = $class->find_by(name => $unit_name);
+  if (!$unit) {
+    $::lxdebug->warn("Unit manager: No unit with name $unit_name");
+    return ();
+  }
+
+  return ("${prefix}name" => [ map { $_->name } @{ $unit->convertible_units } ]);
+}
+
 1;
index 6a40a40ab36409177218fd89b540534eddcc6649..c087b7ffae4decb17da214c4352a95f708fe7d3c 100644 (file)
@@ -19,4 +19,83 @@ sub validate {
   return @errors;
 }
 
+sub calc_date {
+  my ($self, %params) = @_;
+
+  my $reference_date  = $params{reference_date} || DateTime->today_local;
+  $reference_date     = DateTime->from_kivitendo($reference_date) unless ref($reference_date) eq 'DateTime';
+
+  my $terms           = ($params{terms} // 'net') eq 'discount' ? 'terms_skonto' : 'terms_netto';
+  my $date            = $reference_date->add(days => $self->$terms);
+
+  my $dow             = $date->day_of_week;
+  $date               = $date->add(days => 8 - $dow) if $dow > 5;
+
+  return $date;
+}
+
 1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::DB::PaymentTerm - Rose model for the payment_terms table
+
+=head1 SYNOPSIS
+
+  my $terms             = SL::DB::PaymentTerm->new(id => $::form->{payment_id})->load;
+  my $due_date_net      = $erms->calc_date(terms => 'net');      # uses terms_netto
+  my $due_date_discount = $erms->calc_date(terms => 'discount'); # uses terms_skonto
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<calc_date [%params]>
+
+Calculates and returns a due date as an instance of L<DateTime> by
+adding one of C<$self>'s terms fields. Note that the resulting date
+will be the following Monday if the result falls on a weekend.
+
+C<%params> can contain the following parameters:
+
+=over 4
+
+=item C<reference_date>
+
+The reference date from which the due date will be calculated. Can be
+either an instance of L<DateTime> or a scalar in which case the scalar
+is parsed via L<DateTime/from_kivitendo>.
+
+Defaults to the current date if unset.
+
+=item C<terms>
+
+Can be either C<net> or C<discount>. For C<net> the number of days to
+add to the reference date are C<$self-E<gt>terms_netto>. For
+C<discount> C<$self-E<gt>terms_skonto> is used.
+
+Defaults to C<net> if unset.
+
+=back
+
+=item C<validate>
+
+Validates before saving and returns an array of human-readable error
+messages in case of an error.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
index 6367911b9a8d610b183021d73565fab1801af1b0..100652e15e985c070cce283bb9138bc9b3da10f4 100644 (file)
@@ -132,7 +132,7 @@ sub drop_constraints {
       AND (table_name      = ?)
 SQL
 
-  $self->db_query(qq|ALTER TABLE auth."$params{table}" DROP CONSTRAINT "${_}"|) for map { $_->[0] } @{ $constraints };
+  $self->db_query(qq|ALTER TABLE $params{schema}."$params{table}" DROP CONSTRAINT "${_}"|) for map { $_->[0] } @{ $constraints };
 }
 
 1;
index fb8672c6a6fab970c250ad043715ee52b2dd9d06..15f1c8d0825c1f4b3ef97c5c4a806585c7f40179 100644 (file)
--- a/SL/DO.pm
+++ b/SL/DO.pm
@@ -39,6 +39,8 @@ use YAML;
 use SL::AM;
 use SL::Common;
 use SL::CVar;
+use SL::DB::DeliveryOrder;
+use SL::DB::Status;
 use SL::DBUtils;
 use SL::RecordLinks;
 use SL::IC;
@@ -507,59 +509,16 @@ sub delete {
   my $form     = $main::form;
   my $spool    = $::lx_office_conf{paths}->{spool};
 
-  # connect to database
-  my $dbh = $form->get_standard_dbh($myconfig);
-
-  # delete spool files
-  my $query = qq|SELECT s.spoolfile FROM status s WHERE s.trans_id = ?|;
-  my $sth   = prepare_execute_query($form, $dbh, $query, conv_i($form->{id}));
-
-  my $spoolfile;
-  my @spoolfiles = ();
-  my @values;
-
-  while (($spoolfile) = $sth->fetchrow_array) {
-    push @spoolfiles, $spoolfile;
-  }
-  $sth->finish();
-
-  # delete-values
-  @values = (conv_i($form->{id}));
-
-  # delete status entries
-  $query = qq|DELETE FROM status
-              WHERE trans_id = ?|;
-  do_query($form, $dbh, $query, @values);
+  my $rc = SL::DB::Order->new->db->with_transaction(sub {
+    my @spoolfiles = grep { $_ } map { $_->spoolfile } @{ SL::DB::Manager::Status->get_all(where => [ trans_id => $form->{id} ]) };
 
-  # delete individual entries
-  $query = qq|DELETE FROM delivery_order_items_stock
-              WHERE delivery_order_item_id IN (
-                SELECT id FROM delivery_order_items
-                WHERE delivery_order_id = ?
-              )|;
-  do_query($form, $dbh, $query, @values);
-
-  # delete individual entries
-  $query = qq|DELETE FROM delivery_order_items
-              WHERE delivery_order_id = ?|;
-  do_query($form, $dbh, $query, @values);
-
-  # delete DO record
-  $query = qq|DELETE FROM delivery_orders
-              WHERE id = ?|;
-  do_query($form, $dbh, $query, @values);
+    SL::DB::DeliveryOrder->new(id => $form->{id})->delete;
 
-  $query = qq|DELETE FROM shipto
-              WHERE trans_id = ? AND module = 'DO'|;
-  do_query($form, $dbh, $query, @values);
-
-  my $rc = $dbh->commit();
+    my $spool = $::lx_office_conf{paths}->{spool};
+    unlink map { "$spool/$_" } @spoolfiles if $spool;
 
-  if ($rc) {
-    foreach $spoolfile (@spoolfiles) {
-      unlink "$spool/$spoolfile" if $spoolfile;
-    }
-  }
+    1;
+  });
 
   $main::lxdebug->leave_sub();
 
index 874aacee6f5d723463f988de0d92b2bcd110e8d0..79ff7034f37d9edc9df2d2eee2e1350cdb90163a 100644 (file)
@@ -37,6 +37,7 @@
 
 package Form;
 
+use Carp;
 use Data::Dumper;
 
 use CGI;
@@ -53,7 +54,10 @@ use SL::CVar;
 use SL::DB;
 use SL::DBConnect;
 use SL::DBUtils;
+use SL::DB::Customer;
 use SL::DB::Default;
+use SL::DB::PaymentTerm;
+use SL::DB::Vendor;
 use SL::DO;
 use SL::IC;
 use SL::IS;
@@ -1920,22 +1924,12 @@ sub get_duedate {
 
   my ($self, $myconfig, $reference_date) = @_;
 
-  $reference_date = $reference_date ? conv_dateq($reference_date) . '::DATE' : 'current_date';
+  my $terms   = $self->{payment_id}  ? SL::DB::PaymentTerm->new(id => $self->{payment_id}) ->load
+              : $self->{customer_id} ? SL::DB::Customer   ->new(id => $self->{customer_id})->load->payment
+              : $self->{vendor_id}   ? SL::DB::Vendor     ->new(id => $self->{vendor_id})  ->load->payment
+              :                        croak("Missing field in \$::form: payment_id, customer_id or vendor_id");
 
-  my $dbh         = $self->get_standard_dbh($myconfig);
-  my ($payment_id, $duedate);
-
-  if($self->{payment_id}) {
-    $payment_id = $self->{payment_id};
-  } elsif($self->{vendor_id}) {
-    my $query = 'SELECT payment_id FROM vendor WHERE id = ?';
-    ($payment_id) = selectrow_query($self, $dbh, $query, $self->{vendor_id});
-  }
-
-  if ($payment_id) {
-    my $query  = qq|SELECT ${reference_date} + terms_netto FROM payment_terms WHERE id = ?|;
-    ($duedate) = selectrow_query($self, $dbh, $query, $payment_id);
-  }
+  my $duedate = $terms->calc_date(reference_date => $reference_date)->to_kivitendo;
 
   $main::lxdebug->leave_sub();
 
index fec7507ca31a528aa3a553ff869fc5a650d87e3a..694732e1df3395342a3764e158186b0d2ec3839f 100644 (file)
--- a/SL/OE.pm
+++ b/SL/OE.pm
@@ -40,7 +40,9 @@ use YAML;
 use SL::AM;
 use SL::Common;
 use SL::CVar;
+use SL::DB::Order;
 use SL::DB::PeriodicInvoicesConfig;
+use SL::DB::Status;
 use SL::DBUtils;
 use SL::IC;
 
@@ -660,59 +662,16 @@ sub delete {
 
   my ($self, $myconfig, $form) = @_;
 
-  # connect to database
-  my $dbh = $form->get_standard_dbh;
-  $dbh->begin_work;
-
-  # delete spool files
-  my $query = qq|SELECT s.spoolfile FROM status s | .
-              qq|WHERE s.trans_id = ?|;
-  my @values = (conv_i($form->{id}));
-  my $sth = $dbh->prepare($query);
-  $sth->execute(@values) || $self->dberror($query);
-
-  my $spoolfile;
-  my @spoolfiles = ();
-
-  while (($spoolfile) = $sth->fetchrow_array) {
-    push @spoolfiles, $spoolfile;
-  }
-  $sth->finish;
-
-  # delete-values
-  @values = (conv_i($form->{id}));
-
-  # periodic invoices and their configuration
-  do_query($form, $dbh, qq|DELETE FROM periodic_invoices         WHERE config_id IN (SELECT id FROM periodic_invoices_configs WHERE oe_id = ?)|, @values);
-  do_query($form, $dbh, qq|DELETE FROM periodic_invoices_configs WHERE oe_id = ?|, @values);
-
-  # delete status entries
-  $query = qq|DELETE FROM status | .
-           qq|WHERE trans_id = ?|;
-  do_query($form, $dbh, $query, @values);
-
-  # delete individual entries
-  $query = qq|DELETE FROM orderitems | .
-           qq|WHERE trans_id = ?|;
-  do_query($form, $dbh, $query, @values);
+  my $rc = SL::DB::Order->new->db->with_transaction(sub {
+    my @spoolfiles = grep { $_ } map { $_->spoolfile } @{ SL::DB::Manager::Status->get_all(where => [ trans_id => $form->{id} ]) };
 
-  $query = qq|DELETE FROM shipto | .
-           qq|WHERE trans_id = ? AND module = 'OE'|;
-  do_query($form, $dbh, $query, @values);
-
-  # delete OE record
-  $query = qq|DELETE FROM oe | .
-           qq|WHERE id = ?|;
-  do_query($form, $dbh, $query, @values);
+    SL::DB::Order->new(id => $form->{id})->delete;
 
-  my $rc = $dbh->commit;
-
-  if ($rc) {
     my $spool = $::lx_office_conf{paths}->{spool};
-    foreach $spoolfile (@spoolfiles) {
-      unlink "$spool/$spoolfile" if $spoolfile;
-    }
-  }
+    unlink map { "$spool/$_" } @spoolfiles if $spool;
+
+    1;
+  });
 
   $main::lxdebug->leave_sub();
 
index f32149d11f44f8f2e412682d7ad779dded4e7f14..599d0935656ebf4f15ee69fcfdaadea2714eb57e 100644 (file)
@@ -2,18 +2,21 @@ package SL::Presenter::Part;
 
 use strict;
 
+use SL::DB::Part;
+
 use Exporter qw(import);
 our @EXPORT = qw(part_picker);
 
 sub part_picker {
   my ($self, $name, $value, %params) = @_;
-  my $name_e    = $self->escape($name);
+
+  $value = SL::DB::Manager::Part->find_by(id => $value) if !ref $value;
+  my $id = delete($params{id}) || $self->name_to_id($name);
 
   my $ret =
-    $self->input_tag($name, (ref $value && $value->can('id') ? $value->id : ''), class => 'part_autocomplete', type => 'hidden') .
-    $self->input_tag("", delete $params{type}, id => $self->name_to_id("$name_e\_type"), type => 'hidden') .
-    $self->input_tag("", (ref $value && $value->can('description')) ? $value->description : '', id => $self->name_to_id("$name_e\_name"), %params) .
-    $self->input_tag("", delete $params{column}, id => $self->name_to_id("$name_e\_column"), type => 'hidden');
+    $self->input_tag($name, (ref $value && $value->can('id') ? $value->id : ''), class => 'part_autocomplete', type => 'hidden', id => $id) .
+    join('', map { $params{$_} ? $self->input_tag("", delete $params{$_}, id => "${id}_${_}", type => 'hidden') : '' } qw(column type unit convertible_unit)) .
+    $self->input_tag("", (ref $value && $value->can('description')) ? $value->description : '', id => "${id}_name", %params);
 
   $self->html_tag('span', $ret, class => 'part_picker');
 }
@@ -40,17 +43,33 @@ see L<SL::Presenter>
 
 =over 4
 
-=item C<part_picker NAME, VALUE, PARAMS>
+=item C<part_picker $name, $value, %params>
+
+All-in-one picker widget for parts. The name will be both id and name
+of the resulting hidden C<id> input field (but the ID can be
+overwritten with C<$params{id}>).
+
+An additional dummy input will be generated which is used to find
+parts. For a detailed description of it's behaviour, see section
+C<PART PICKER SPECIFICATION>.
+
+C<$value> can be a parts id or a C<Rose::DB:Object> instance.
 
 All-in-one picker widget for parts. The name will be both id and name of the
 resulting hidden C<id> input field. An additional dummy input will be generated
 which is used to find parts. For a detailed description of it's behaviour, see
 section L</PART PICKER SPECIFICATION>.
 
-C<VALUE> can be an id or C<Rose::DB:Object> instance.
+If C<%params> contains C<type> only parts of this type will be used
+for autocompletion. You may comma separate multiple types as in
+C<part,assembly>.
+
+If C<%params> contains C<unit> only parts with this unit will be used
+for autocompletion. You may comma separate multiple units as in
+C<h,min>.
 
-If C<PARAMS> contains C<type> only parts of this type will be used for
-autocompletion. You may comma separate multiple types as in C<part,assembly>.
+If C<%params> contains C<convertible_unit> only parts with a unit
+that's convertible to unit will be used for autocompletion.
 
 Obsolete parts will by default not displayed for selection. However they are
 accepted as default values and can persist during updates. As with other
index 901da5e79aa3da68184a858e12658dc72cf7d9f8..b9ef3e92476cd7f0cb60d1db8ebb62f6eb90bcba 100644 (file)
@@ -12,6 +12,8 @@ namespace('kivi', function(k){
     var real_id = $real.attr('id');
     var $dummy  = $('#' + real_id + '_name');
     var $type   = $('#' + real_id + '_type');
+    var $unit   = $('#' + real_id + '_unit');
+    var $convertible_unit = $('#' + real_id + '_convertible_unit');
     var $column = $('#' + real_id + '_column');
     var state   = STATES.PICKED;
     var last_real = $real.val();
@@ -28,13 +30,21 @@ namespace('kivi', function(k){
     };
 
     function ajax_data(term) {
-      return {
+      var data = {
         'filter.all:substr::ilike': term,
-        'filter.type':  $type.val().split(','),
         'filter.obsolete': 0,
-        column:   $column.val()===undefined ? '' : $column.val(),
+        'filter.unit_obj.convertible_to': $convertible_unit && $convertible_unit.val() ? $convertible_unit.val() : '',
+        column:   $column && $column.val() ? $column.val() : '',
         current:  $real.val(),
-      }
+      };
+
+      if ($type && $type.val())
+        data['filter.type'] = $type.val().split(',');
+
+      if ($unit && $unit.val())
+        data['filter.unit'] = $unit.val().split(',');
+
+      return data;
     }
 
     function set_item (item) {
@@ -145,6 +155,8 @@ namespace('kivi', function(k){
       real:           function() { return $real },
       dummy:          function() { return $dummy },
       type:           function() { return $type },
+      unit:           function() { return $unit },
+      convertible_unit: function() { return $convertible_unit },
       column:         function() { return $column },
       update_results: update_results,
       set_item:       set_item,
index b89a5b41ef49b2a976bdea84af4885287cef58c8..71f1d3104b0d0c79a42263e88b31132763477c61 100644 (file)
@@ -185,14 +185,6 @@ function open_jqm_window(params) {
   return true;
 }
 
-function close_jqm_window(params) {
-  params = params || { };
-  var url = params.url;
-  var id  = params.id ? params.id : 'jqm_popup_dialog';
-
-  $('#' + id).jqmClose()();
-}
-
 $(document).ready(function () {
   // initialize all jQuery UI tab elements:
   $(".tabwidget").each(function(idx, element) { $(element).tabs(); });
diff --git a/sql/Pg-upgrade2/oe_do_delete_via_trigger.pl b/sql/Pg-upgrade2/oe_do_delete_via_trigger.pl
new file mode 100644 (file)
index 0000000..34f4a2a
--- /dev/null
@@ -0,0 +1,77 @@
+# @tag: oe_do_delete_via_trigger
+# @description: Aus oe/delivery_orders via Trigger löschen können
+# @depends: release_3_0_0
+
+package SL::DBUpgrade2::oe_do_delete_via_trigger;
+
+use utf8;
+use strict;
+
+use parent qw(SL::DBUpgrade2::Base);
+
+sub run {
+  my ($self) = @_;
+
+  $self->drop_constraints(table => $_) for qw(periodic_invoices periodic_invoices_configs orderitems delivery_order_items delivery_order_items_stock);
+
+  my @queries = (
+    q|ALTER TABLE periodic_invoices          ADD CONSTRAINT periodic_invoices_ar_id_fkey                           FOREIGN KEY (ar_id)                  REFERENCES ar                        (id) ON DELETE CASCADE|,
+    q|ALTER TABLE periodic_invoices          ADD CONSTRAINT periodic_invoices_config_id_fkey                       FOREIGN KEY (config_id)              REFERENCES periodic_invoices_configs (id) ON DELETE CASCADE|,
+
+    q|ALTER TABLE periodic_invoices_configs  ADD CONSTRAINT periodic_invoices_configs_ar_chart_id_fkey             FOREIGN KEY (ar_chart_id)            REFERENCES chart                     (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE periodic_invoices_configs  ADD CONSTRAINT periodic_invoices_configs_oe_id_fkey                   FOREIGN KEY (oe_id)                  REFERENCES oe                        (id) ON DELETE CASCADE|,
+    q|ALTER TABLE periodic_invoices_configs  ADD CONSTRAINT periodic_invoices_configs_printer_id_fkey              FOREIGN KEY (printer_id)             REFERENCES printers                  (id) ON DELETE SET NULL|,
+
+    q|ALTER TABLE orderitems                 ADD CONSTRAINT orderitems_parts_id_fkey                               FOREIGN KEY (parts_id)               REFERENCES parts                     (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE orderitems                 ADD CONSTRAINT orderitems_price_factor_id_fkey                        FOREIGN KEY (price_factor_id)        REFERENCES price_factors             (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE orderitems                 ADD CONSTRAINT orderitems_pricegroup_id_fkey                          FOREIGN KEY (pricegroup_id)          REFERENCES pricegroup                (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE orderitems                 ADD CONSTRAINT orderitems_project_id_fkey                             FOREIGN KEY (project_id)             REFERENCES project                   (id) ON DELETE SET NULL|,
+    q|ALTER TABLE orderitems                 ADD CONSTRAINT orderitems_trans_id_fkey                               FOREIGN KEY (trans_id)               REFERENCES oe                        (id) ON DELETE CASCADE|,
+
+    q|ALTER TABLE delivery_order_items       ADD CONSTRAINT delivery_order_items_delivery_order_id_fkey            FOREIGN KEY (delivery_order_id)      REFERENCES delivery_orders           (id) ON DELETE CASCADE|,
+    q|ALTER TABLE delivery_order_items       ADD CONSTRAINT delivery_order_items_parts_id_fkey                     FOREIGN KEY (parts_id)               REFERENCES parts                     (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE delivery_order_items       ADD CONSTRAINT delivery_order_items_price_factor_id_fkey              FOREIGN KEY (price_factor_id)        REFERENCES price_factors             (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE delivery_order_items       ADD CONSTRAINT delivery_order_items_pricegroup_id_fkey                FOREIGN KEY (pricegroup_id)          REFERENCES pricegroup                (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE delivery_order_items       ADD CONSTRAINT delivery_order_items_project_id_fkey                   FOREIGN KEY (project_id)             REFERENCES project                   (id) ON DELETE SET NULL|,
+
+    q|ALTER TABLE delivery_order_items_stock ADD CONSTRAINT delivery_order_items_stock_bin_id_fkey                 FOREIGN KEY (bin_id)                 REFERENCES bin                       (id) ON DELETE RESTRICT|,
+    q|ALTER TABLE delivery_order_items_stock ADD CONSTRAINT delivery_order_items_stock_delivery_order_item_id_fkey FOREIGN KEY (delivery_order_item_id) REFERENCES delivery_order_items      (id) ON DELETE CASCADE|,
+    q|ALTER TABLE delivery_order_items_stock ADD CONSTRAINT delivery_order_items_stock_warehouse_id_fkey           FOREIGN KEY (warehouse_id)           REFERENCES warehouse                 (id) ON DELETE RESTRICT|,
+
+    q|CREATE OR REPLACE FUNCTION oe_before_delete_trigger() RETURNS trigger AS $$
+        BEGIN
+          DELETE FROM status WHERE trans_id = OLD.id;
+          DELETE FROM shipto WHERE (trans_id = OLD.id) AND (module = 'OE');
+
+          RETURN OLD;
+        END;
+      $$ LANGUAGE plpgsql|,
+
+    q|DROP TRIGGER IF EXISTS delete_oe_dependencies ON oe|,
+
+    q|CREATE TRIGGER delete_oe_dependencies
+      BEFORE DELETE ON oe
+      FOR EACH ROW EXECUTE PROCEDURE oe_before_delete_trigger()|,
+
+    q|CREATE OR REPLACE FUNCTION delivery_orders_before_delete_trigger() RETURNS trigger AS $$
+        BEGIN
+          DELETE FROM status                     WHERE trans_id = OLD.id;
+          DELETE FROM delivery_order_items_stock WHERE delivery_order_item_id IN (SELECT id FROM delivery_order_items WHERE delivery_order_id = OLD.id);
+          DELETE FROM shipto                     WHERE (trans_id = OLD.id) AND (module = 'OE');
+
+          RETURN OLD;
+        END;
+      $$ LANGUAGE plpgsql|,
+
+    q|DROP TRIGGER IF EXISTS delete_delivery_orders_dependencies ON delivery_orders|,
+
+    q|CREATE TRIGGER delete_delivery_orders_dependencies
+      BEFORE DELETE ON delivery_orders
+      FOR EACH ROW EXECUTE PROCEDURE delivery_orders_before_delete_trigger()|);
+
+  $self->db_query($_) for @queries;
+
+  return 1;
+}
+
+1;