X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FController%2FPart.pm;h=20f6752f1e113426a58281f36b78cf322f3eded1;hb=117332fcc34457aadb85db18dbc42f48d32b732e;hp=5622193c48fb9a0f6c349e68d1671f9ded0a1170;hpb=13fb6d811d39a8af7144451ada59f2f7d4eb491a;p=kivitendo-erp.git diff --git a/SL/Controller/Part.pm b/SL/Controller/Part.pm index 5622193c4..20f6752f1 100644 --- a/SL/Controller/Part.pm +++ b/SL/Controller/Part.pm @@ -5,6 +5,7 @@ use parent qw(SL::Controller::Base); use Clone qw(clone); use SL::DB::Part; +use SL::DB::PartsGroup; use SL::Controller::Helper::GetModels; use SL::Locale::String qw(t8); use SL::JSON; @@ -13,6 +14,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 +25,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) ], ); @@ -192,6 +194,7 @@ sub render_form { my ($self, %params) = @_; $self->_set_javascript; + $self->_setup_form_action_bar; my (%assortment_vars, %assembly_vars); %assortment_vars = %{ $self->prepare_assortment_render_vars } if $self->part->is_assortment; @@ -214,7 +217,6 @@ sub render_form { $self->render( 'part/form', title => $title_hash{$self->part->part_type}, - show_edit_buttons => $::auth->assert('part_service_assembly_edit'), %assortment_vars, %assembly_vars, translations_map => { map { ($_->language_id => $_) } @{$self->part->translations} }, @@ -250,7 +252,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 { @@ -259,7 +261,7 @@ sub action_add_multi_assortment_items { my $item_objects = $self->parse_add_items_to_objects(part_type => 'assortment'); my $html = $self->render_assortment_items_to_html($item_objects); - $self->js->run('kivi.Part.close_multi_items_dialog') + $self->js->run('kivi.Part.close_picker_dialogs') ->append('#assortment_rows', $html) ->run('kivi.Part.renumber_positions') ->run('kivi.Part.assortment_recalc') @@ -270,9 +272,16 @@ 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') + $self->js->run('kivi.Part.close_picker_dialogs') ->append('#assembly_rows', $html) ->run('kivi.Part.renumber_positions') ->run('kivi.Part.assembly_recalc') @@ -313,6 +322,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 +331,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 +339,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; @@ -352,11 +371,9 @@ sub action_add_assembly_item { } sub action_show_multi_items_dialog { - require SL::DB::PartsGroup; $_[0]->render('part/_multi_items_dialog', { layout => 0 }, - part_type => 'assortment', - partfilter => '', # can I get at the current input of the partpicker here? - all_partsgroups => SL::DB::Manager::PartsGroup->get_all); + all_partsgroups => SL::DB::Manager::PartsGroup->get_all + ); } sub action_multi_items_update_result { @@ -457,20 +474,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; } @@ -480,21 +500,19 @@ sub action_ajax_autocomplete { # if someone types something, and hits enter, assume he entered the full name. # if something matches, treat that as sole match - # unfortunately get_models can't do more than one per package atm, so we d it - # the oldfashioned way. + # since we need a second get models instance with different filters for that, + # we only modify the original filter temporarily in place if ($::form->{prefer_exact}) { + local $::form->{filter}{'all::ilike'} = delete local $::form->{filter}{'all:substr:multi::ilike'}; + + my $exact_models = SL::Controller::Helper::GetModels->new( + controller => $self, + sorted => 0, + paginated => { per_page => 2 }, + with_objects => [ qw(unit_obj classification) ], + ); my $exact_matches; - if (1 == scalar @{ $exact_matches = SL::DB::Manager::Part->get_all( - query => [ - obsolete => 0, - SL::DB::Manager::Part->type_filter($::form->{filter}{part_type}), - or => [ - description => { ilike => $::form->{filter}{'all:substr:multi::ilike'} }, - partnumber => { ilike => $::form->{filter}{'all:substr:multi::ilike'} }, - ] - ], - limit => 2, - ) }) { + if (1 == scalar @{ $exact_matches = $exact_models->get }) { $self->parts($exact_matches); } } @@ -520,11 +538,11 @@ sub action_test_page { } sub action_part_picker_search { - $_[0]->render('part/part_picker_search', { layout => 0 }, parts => $_[0]->parts); + $_[0]->render('part/part_picker_search', { layout => 0 }); } sub action_part_picker_result { - $_[0]->render('part/_part_picker_result', { layout => 0 }); + $_[0]->render('part/_part_picker_result', { layout => 0 }, parts => $_[0]->parts); } sub action_show { @@ -578,6 +596,7 @@ sub add { check_has_valid_part_type($self->part->part_type); $self->_set_javascript; + $self->_setup_form_action_bar; my %title_hash = ( part => t8('Add Part'), assembly => t8('Add Assembly'), @@ -587,15 +606,14 @@ sub add { $self->render( 'part/form', - title => $title_hash{$self->part->part_type}, - show_edit_buttons => $::auth->assert('part_service_assembly_edit'), + title => $title_hash{$self->part->part_type}, ); } 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 +665,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 +807,7 @@ sub init_models { partnumber => t8('Partnumber'), description => t8('Description'), }, - with_objects => [ qw(unit_obj) ], + with_objects => [ qw(unit_obj classification) ], ); } @@ -872,7 +890,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 +913,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 +930,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 +960,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 +997,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') @@ -1104,6 +1127,52 @@ sub parse_add_items_to_objects { return \@item_objects; } +sub _setup_form_action_bar { + my ($self) = @_; + + my $may_edit = $::auth->assert('part_service_assembly_edit', 'may fail'); + + for my $bar ($::request->layout->get('actionbar')) { + $bar->add( + combobox => [ + action => [ + t8('Save'), + call => [ 'kivi.Part.save' ], + disabled => !$may_edit ? t8('You do not have the permissions to access this function.') : undef, + accesskey => 'enter', + ], + action => [ + t8('Use as new'), + call => [ 'kivi.Part.use_as_new' ], + disabled => !$self->part->id ? t8('The object has not been saved yet.') + : !$may_edit ? t8('You do not have the permissions to access this function.') + : undef, + ], + ], # end of combobox "Save" + + action => [ + t8('Delete'), + call => [ 'kivi.Part.delete' ], + confirm => t8('Do you really want to delete this object?'), + disabled => !$self->part->id ? t8('This object has not been saved yet.') + : !$may_edit ? t8('You do not have the permissions to access this function.') + : !$self->part->orphaned ? t8('This object has already been used.') + : undef, + ], + + 'separator', + + action => [ + t8('History'), + call => [ 'kivi.Part.open_history_popup' ], + disabled => !$self->part->id ? t8('This object has not been saved yet.') + : !$may_edit ? t8('You do not have the permissions to access this function.') + : undef, + ], + ); + } +} + 1; __END__