Dateimanagement: Controller zum Laden und Generierung der Dateien
[kivitendo-erp.git] / SL / Controller / Part.pm
index 5622193..12494dd 100644 (file)
@@ -13,6 +13,7 @@ use SL::Helper::Flash;
 use Data::Dumper;
 use DateTime;
 use SL::DB::History;
+use SL::DB::Helper::ValidateAssembly qw(validate_assembly);
 use SL::CVar;
 use Carp;
 
@@ -23,7 +24,7 @@ use Rose::Object::MakeMethods::Generic (
                                   assortment assortment_items assembly assembly_items
                                   all_pricegroups all_translations all_partsgroups all_units
                                   all_buchungsgruppen all_payment_terms all_warehouses
-                                  all_languages all_units all_pricefactors) ],
+                                  all_languages all_units all_price_factors) ],
   'scalar'                => [ qw(warehouse bin) ],
 );
 
@@ -250,7 +251,7 @@ sub action_update_item_totals {
     ->html('#items_sum_diff',            $::form->format_amount(\%::myconfig, $sum_diff,      2, 0))
     ->html('#items_sellprice_sum_basic', $::form->format_amount(\%::myconfig, $sellprice_sum, 2, 0))
     ->html('#items_lastcost_sum_basic',  $::form->format_amount(\%::myconfig, $lastcost_sum,  2, 0))
-    ->render();
+    ->no_flash_clear->render();
 }
 
 sub action_add_multi_assortment_items {
@@ -270,7 +271,14 @@ sub action_add_multi_assembly_items {
   my ($self) = @_;
 
   my $item_objects = $self->parse_add_items_to_objects(part_type => 'assembly');
-  my $html         = $self->render_assembly_items_to_html($item_objects);
+  my @checked_objects;
+  foreach my $item (@{$item_objects}) {
+    my $errstr = validate_assembly($item->part,$self->part);
+    $self->js->flash('error',$errstr) if     $errstr;
+    push (@checked_objects,$item)     unless $errstr;
+  }
+
+  my $html = $self->render_assembly_items_to_html(\@checked_objects);
 
   $self->js->run('kivi.Part.close_multi_items_dialog')
            ->append('#assembly_rows', $html)
@@ -313,6 +321,7 @@ sub action_add_assortment_item {
     ->html('#items_lastcost_sum_basic',  $::form->format_amount(\%::myconfig, $items_lastcost_sum,  2, 0))
     ->render;
 }
+
 sub action_add_assembly_item {
   my ($self) = @_;
 
@@ -321,6 +330,7 @@ sub action_add_assembly_item {
   carp('Too many objects passed to add_assembly_item') if @{$::form->{add_items}} > 1;
 
   my $add_item_id = $::form->{add_items}->[0]->{parts_id};
+
   my $duplicate_warning = 0; # duplicates are allowed, just warn
   if ( $add_item_id && grep { $add_item_id == $_->parts_id } @{ $self->assembly_items } ) {
     $duplicate_warning++;
@@ -328,6 +338,14 @@ sub action_add_assembly_item {
 
   my $number_of_items = scalar @{$self->assembly_items};
   my $item_objects    = $self->parse_add_items_to_objects(part_type => 'assembly');
+  if ($add_item_id ) {
+    foreach my $item (@{$item_objects}) {
+      my $errstr = validate_assembly($item->part,$self->part);
+      return $self->js->flash('error',$errstr)->render if $errstr;
+    }
+  }
+
+
   my $html            = $self->render_assembly_items_to_html($item_objects, $number_of_items);
 
   $self->js->flash('info', t8("This part has already been added.")) if $duplicate_warning;
@@ -457,20 +475,23 @@ sub action_reorder_items {
 sub action_warehouse_changed {
   my ($self) = @_;
 
-  $self->warehouse(SL::DB::Manager::Warehouse->find_by_or_create(id => $::form->{warehouse_id}));
-  die unless ref($self->warehouse) eq 'SL::DB::Warehouse';
+  if ($::form->{warehouse_id} ) {
+    $self->warehouse(SL::DB::Manager::Warehouse->find_by_or_create(id => $::form->{warehouse_id}));
+    die unless ref($self->warehouse) eq 'SL::DB::Warehouse';
 
-  if ( $self->warehouse->id and @{$self->warehouse->bins} ) {
-    $self->bin($self->warehouse->bins->[0]);
-    $self->js
-      ->html('#bin', $self->build_bin_select)
-      ->focus('#part_bin_id');
-  } else {
-    # no warehouse was selected, empty the bin field and reset the id
-    $self->js
-        ->val('#part_bin_id', undef)
-        ->html('#bin', '');
-  };
+    if ( $self->warehouse->id and @{$self->warehouse->bins} ) {
+      $self->bin($self->warehouse->bins->[0]);
+      $self->js
+        ->html('#bin', $self->build_bin_select)
+        ->focus('#part_bin_id');
+      return $self->js->render;
+    }
+  }
+
+  # no warehouse was selected, empty the bin field and reset the id
+  $self->js
+       ->val('#part_bin_id', undef)
+       ->html('#bin', '');
 
   return $self->js->render;
 }
@@ -488,6 +509,7 @@ sub action_ajax_autocomplete {
       query => [
         obsolete => 0,
         SL::DB::Manager::Part->type_filter($::form->{filter}{part_type}),
+        SL::DB::Manager::PartClassification->classification_filter($::form->{filter}{classification_id}),
         or => [
           description => { ilike => $::form->{filter}{'all:substr:multi::ilike'} },
           partnumber  => { ilike => $::form->{filter}{'all:substr:multi::ilike'} },
@@ -595,7 +617,7 @@ sub add {
 
 sub _set_javascript {
   my ($self) = @_;
-  $::request->layout->use_javascript("${_}.js")  for qw(kivi.Part kivi.PriceRule ckeditor/ckeditor ckeditor/adapters/jquery);
+  $::request->layout->use_javascript("${_}.js")  for qw(kivi.Part kivi.File kivi.PriceRule ckeditor/ckeditor ckeditor/adapters/jquery);
   $::request->layout->add_javascripts_inline("\$(function(){kivi.PriceRule.load_price_rules_for_part(@{[ $self->part->id ]})});") if $self->part->id;
 }
 
@@ -647,8 +669,8 @@ sub parse_form {
   my $params = delete($::form->{part}) || { };
 
   delete $params->{id};
-  # never overwrite existing partnumber, should be a read-only field anyway
-  delete $params->{partnumber} if $self->part->partnumber;
+  # never overwrite existing partnumber for parts in use, should be a read-only field in that case anyway
+  delete $params->{partnumber} if $self->part->partnumber and not $self->orphaned;
   $self->part->assign_attributes(%{ $params});
   $self->part->bin_id(undef) unless $self->part->warehouse_id;
 
@@ -789,7 +811,7 @@ sub init_models {
       partnumber  => t8('Partnumber'),
       description  => t8('Description'),
     },
-    with_objects => [ qw(unit_obj) ],
+    with_objects => [ qw(unit_obj classification) ],
   );
 }
 
@@ -872,7 +894,8 @@ sub init_all_languages {
 }
 
 sub init_all_partsgroups {
-  SL::DB::Manager::PartsGroup->get_all_sorted;
+  my ($self) = @_;
+  SL::DB::Manager::PartsGroup->get_all_sorted(query => [ or => [ id => $self->part->partsgroup_id, obsolete => 0 ] ]);
 }
 
 sub init_all_buchungsgruppen {
@@ -894,7 +917,8 @@ sub init_all_units {
 }
 
 sub init_all_payment_terms {
-  SL::DB::Manager::PaymentTerm->get_all_sorted;
+  my ($self) = @_;
+  SL::DB::Manager::PaymentTerm->get_all_sorted(query => [ or => [ id => $self->part->payment_id, obsolete => 0 ] ]);
 }
 
 sub init_all_price_factors {
@@ -910,7 +934,7 @@ sub init_multi_items_models {
   SL::Controller::Helper::GetModels->new(
     controller     => $_[0],
     model          => 'Part',
-    with_objects   => [ qw(unit_obj partsgroup) ],
+    with_objects   => [ qw(unit_obj partsgroup classification) ],
     disable_plugin => 'paginated',
     source         => $::form->{multi_items},
     sorted         => {
@@ -940,7 +964,7 @@ sub form_check_assortment_items_exist {
   my ($self) = @_;
 
   return 1 unless $::form->{part}{part_type} eq 'assortment';
-  # skip check for existing parts that have been used
+  # skip item check for existing assortments that have been used
   return 1 if ($self->part->id and !$self->part->orphaned);
 
   # new or orphaned parts must have items in $::form->{assortment_items}
@@ -977,6 +1001,9 @@ sub form_check_assembly_items_exist {
 
   return 1 unless $::form->{part}->{part_type} eq 'assembly';
 
+  # skip item check for existing assembly that have been used
+  return 1 if ($self->part->id and !$self->part->orphaned);
+
   unless ( $::form->{assembly_items} and scalar @{$::form->{assembly_items}} ) {
     $self->js->run('kivi.Part.set_tab_active_by_name', 'assembly_tab')
              ->focus('#add_assembly_item_name')