X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FController%2FRequirementSpec.pm;h=f762b9794a14a4fdd19d25033757d5bb62306f32;hb=fec397bf76c75df4102a45444512572a686cbf24;hp=944e9ddbe4a0c90d74165f75fe45cbc6ca759c68;hpb=76105d1596c47e6883d527d21de683baa65c9c90;p=kivitendo-erp.git diff --git a/SL/Controller/RequirementSpec.pm b/SL/Controller/RequirementSpec.pm index 944e9ddbe..f762b9794 100644 --- a/SL/Controller/RequirementSpec.pm +++ b/SL/Controller/RequirementSpec.pm @@ -10,14 +10,12 @@ use File::Spec (); use SL::ClientJS; use SL::Common (); use SL::Controller::Helper::GetModels; -use SL::Controller::Helper::Filtered; -use SL::Controller::Helper::Paginated; -use SL::Controller::Helper::Sorted; -use SL::Controller::Helper::ParseFilter; use SL::Controller::Helper::ReportGenerator; use SL::Controller::Helper::RequirementSpec; use SL::DB::Customer; use SL::DB::Project; +use SL::DB::ProjectStatus; +use SL::DB::ProjectType; use SL::DB::RequirementSpecComplexity; use SL::DB::RequirementSpecRisk; use SL::DB::RequirementSpecStatus; @@ -29,28 +27,15 @@ use SL::Template::LaTeX; use Rose::Object::MakeMethods::Generic ( - scalar => [ qw(requirement_spec_item customers types statuses visible_item visible_section) ], - 'scalar --get_set_init' => [ qw(requirement_spec complexities risks projects copy_source js current_text_block_output_position) ], + scalar => [ qw(requirement_spec_item visible_item visible_section) ], + 'scalar --get_set_init' => [ qw(requirement_spec customers types statuses complexities risks projects project_types project_statuses default_project_type default_project_status copy_source js + current_text_block_output_position models time_based_units) ], ); __PACKAGE__->run_before('setup'); -__PACKAGE__->run_before('load_select_options', only => [ qw(new ajax_edit create update list) ]); - -__PACKAGE__->make_filtered( - MODEL => 'RequirementSpec', - LAUNDER_TO => 'filter' -); -__PACKAGE__->make_paginated( - MODEL => 'RequirementSpec', - ONLY => [ qw(list) ], -); -__PACKAGE__->make_sorted( - MODEL => 'RequirementSpec', - ONLY => [ qw(list) ], - - DEFAULT_BY => 'customer', - DEFAULT_DIR => 1, +__PACKAGE__->run_before('set_default_filter_args', only => [ qw(list) ]); +my %sort_columns = ( customer => t8('Customer'), title => t8('Title'), type => t8('Requirement Spec Type'), @@ -68,17 +53,8 @@ __PACKAGE__->make_sorted( sub action_list { my ($self) = @_; - my $requirement_specs = $self->get_models( - query => [ - and => [ - working_copy_id => undef, - is_template => $::form->{is_template} ? 1 : 0, - ]], - with_objects => [ 'customer', 'type', 'status', 'project' ], - ); - $self->prepare_report; - $self->report_generator_list_objects(report => $self->{report}, objects => $requirement_specs); + $self->report_generator_list_objects(report => $self->{report}, objects => $self->models->get); } sub action_new { @@ -87,7 +63,7 @@ sub action_new { $self->requirement_spec(SL::DB::RequirementSpec->new(is_template => $::form->{is_template})); if ($self->copy_source) { - $self->requirement_spec->$_($self->copy_source->$_) for qw(type_id status_id customer_id title hourly_rate) + $self->requirement_spec->$_($self->copy_source->$_) for qw(type_id status_id customer_id title hourly_rate is_template) } $self->render('requirement_spec/new', title => $self->requirement_spec->is_template ? t8('Create a new requirement spec template') : t8('Create a new requirement spec')); @@ -110,6 +86,17 @@ sub action_ajax_edit { ->render($self); } +sub action_ajax_edit_project_link { + my ($self) = @_; + + my $html = $self->render('requirement_spec/_project_link_form', { output => 0 }, submit_as => 'ajax'); + + $self->js + ->hide('#basic_settings') + ->after('#basic_settings', $html) + ->render($self); +} + sub action_ajax_show_time_and_cost_estimate { my ($self) = @_; @@ -120,11 +107,14 @@ sub action_ajax_edit_time_and_cost_estimate { my ($self) = @_; my $html = $self->render('requirement_spec/_edit_time_and_cost_estimate', { output => 0 }); + my $first = ($self->requirement_spec->sections_sorted || [])->[0]; + $first = ($first->children_sorted || [])->[0] if $first; $self->js ->hide('#time_cost_estimate') ->after('#time_cost_estimate', $html) ->on('#time_cost_estimate INPUT[type=text]', 'keydown', 'kivi.requirement_spec.time_cost_estimate_input_key_down') + ->action_if($first && $first->id, 'focus', '#time_and_cost_estimate_form_complexity_id_' . $first->id) ->render($self); } @@ -146,9 +136,12 @@ sub action_ajax_save_time_and_cost_estimate { $self->requirement_spec(SL::DB::RequirementSpec->new(id => $self->requirement_spec->id)->load); - my $html = $self->render('requirement_spec/_show_time_and_cost_estimate', { output => 0 }); - $self->js->replaceWith('#time_cost_estimate', $html) - ->remove('#time_cost_estimate_form_container'); + my $html = $self->render('requirement_spec/_show_time_and_cost_estimate', { output => 0 }, initially_hidden => !!$::form->{keep_open}); + $self->js->replaceWith('#time_cost_estimate', $html); + + return $self->js->render($self) if $::form->{keep_open}; + + $self->js->remove('#time_cost_estimate_form_container'); if ($self->visible_section) { $html = $self->render('requirement_spec_item/_section', { output => 0 }, requirement_spec_item => $self->visible_section); @@ -162,7 +155,7 @@ sub action_show { my ($self) = @_; my $title = $self->requirement_spec->is_template ? t8('Show requirement spec template') : t8('Show requirement spec'); - my $item = $::form->{requirement_spec_item_id} ? SL::DB::RequirementSpecItem->new(id => $::form->{requirement_spec_item_id})->load : @{ $self->requirement_spec->sections }[0]; + my $item = $::form->{requirement_spec_item_id} ? SL::DB::RequirementSpecItem->new(id => $::form->{requirement_spec_item_id})->load : @{ $self->requirement_spec->sections_sorted }[0]; $self->requirement_spec_item($item); $self->render('requirement_spec/show', title => $title); @@ -180,6 +173,17 @@ sub action_update { $self->create_or_update; } +sub action_update_project_link { + my $self = shift; + my $action = delete($::form->{project_link_action}) || 'keep'; + + return $self->update_project_link_none_keep_existing($action) if $action =~ m{none|keep|existing}; + return $self->update_project_link_new($action) if $action eq 'new'; + return $self->update_project_link_create($action) if $action eq 'create'; + + die "Unknown project link action '$action'"; +} + sub action_destroy { my ($self) = @_; @@ -230,7 +234,10 @@ sub action_create_pdf { sub action_select_template_to_paste { my ($self) = @_; - my @templates = grep { @{ $_->sections } || @{ $_->text_blocks } } @{ SL::DB::Manager::RequirementSpec->get_all(where => [ is_template => 1 ], sort_by => 'lower(title)') }; + my @templates = @{ SL::DB::Manager::RequirementSpec->get_all( + where => [ is_template => 1, SL::DB::Manager::RequirementSpec->not_empty_filter ], + sort_by => 'lower(requirement_specs.title)', + ) }; $self->render('requirement_spec/select_template_to_paste', { layout => 0 }, TEMPLATES => \@templates); } @@ -249,6 +256,12 @@ sub action_paste_template { $self->render_first_pasted_section_as_list($result{sections}->[0]); } + my $parts_list = $self->render('requirement_spec_part/show', { output => 0 }); + $self->js + ->replaceWith('#additional_parts_list_container', $parts_list) + ->show( '#additional_parts_list_container') + ->remove( '#additional_parts_form_container'); + $self->invalidate_version->render($self); } @@ -259,27 +272,33 @@ sub action_paste_template { sub setup { my ($self) = @_; - $::auth->assert('sales_quotation_edit'); + $::auth->assert('requirement_spec_edit'); $::request->{layout}->use_stylesheet("${_}.css") for qw(jquery.contextMenu requirement_spec); - $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu requirement_spec); + $::request->{layout}->use_javascript("${_}.js") for qw(jquery.jstree jquery/jquery.contextMenu jquery/jquery.hotkeys requirement_spec ckeditor/ckeditor ckeditor/adapters/jquery); $self->init_visible_section; return 1; } -sub init_complexities { +sub init_js { SL::ClientJS->new } +sub init_complexities { SL::DB::Manager::RequirementSpecComplexity->get_all_sorted } +sub init_default_project_status { SL::DB::Manager::ProjectStatus->find_by(name => 'planning') } +sub init_default_project_type { SL::DB::ProjectType->new(id => 1)->load } +sub init_project_statuses { SL::DB::Manager::ProjectStatus->get_all_sorted } +sub init_project_types { SL::DB::Manager::ProjectType->get_all_sorted } +sub init_projects { SL::DB::Manager::Project->get_all_sorted } +sub init_risks { SL::DB::Manager::RequirementSpecRisk->get_all_sorted } +sub init_statuses { SL::DB::Manager::RequirementSpecStatus->get_all_sorted } +sub init_time_based_units { SL::DB::Manager::Unit->time_based_units } +sub init_types { SL::DB::Manager::RequirementSpecType->get_all_sorted } + +sub init_customers { my ($self) = @_; - return SL::DB::Manager::RequirementSpecComplexity->get_all_sorted; -} -sub init_risks { - my ($self) = @_; - return SL::DB::Manager::RequirementSpecRisk->get_all_sorted; -} + my @filter = ('!obsolete' => 1); + @filter = ( or => [ @filter, id => $self->requirement_spec->customer_id ] ) if $self->requirement_spec && $self->requirement_spec->customer_id; -sub init_projects { - my ($self) = @_; - $self->projects(SL::DB::Manager::Project->get_all_sorted); + return SL::DB::Manager::Customer->get_all_sorted(where => \@filter); } sub init_requirement_spec { @@ -292,27 +311,11 @@ sub init_copy_source { $self->copy_source(SL::DB::RequirementSpec->new(id => $::form->{copy_source_id})->load) if $::form->{copy_source_id}; } -sub init_js { - my ($self) = @_; - $self->js(SL::ClientJS->new); -} - sub init_current_text_block_output_position { my ($self) = @_; $self->current_text_block_output_position($::form->{current_content_type} !~ m/^(?:text-blocks|tb)-(front|back)/ ? -1 : $1 eq 'front' ? 0 : 1); } -sub load_select_options { - my ($self) = @_; - - my @filter = ('!obsolete' => 1); - @filter = ( or => [ @filter, id => $self->requirement_spec->customer_id ] ) if $self->requirement_spec && $self->requirement_spec->customer_id; - - $self->customers(SL::DB::Manager::Customer->get_all_sorted(where => \@filter)); - $self->statuses( SL::DB::Manager::RequirementSpecStatus->get_all_sorted); - $self->types( SL::DB::Manager::RequirementSpecType->get_all_sorted); -} - # # helpers # @@ -376,10 +379,13 @@ sub create_or_update { sub prepare_report { my ($self) = @_; - my $callback = $self->get_callback; - my $is_template = $::form->{is_template}; my $report = SL::ReportGenerator->new(\%::myconfig, $::form); + + $self->models->disable_plugin('paginated') if $report->{options}{output_format} =~ /^(pdf|csv)$/i; + $self->models->finalize; # for filter laundering + my $callback = $self->models->get_callback; + $self->{report} = $report; my @columns = $is_template ? qw(title mtime) : qw(title customer status type projectnumber mtime version); @@ -403,14 +409,14 @@ sub prepare_report { ); } - map { $column_defs{$_}->{text} ||= $::locale->text( $self->get_sort_spec->{$_}->{title} ) } keys %column_defs; + map { $column_defs{$_}->{text} ||= $::locale->text( $self->models->get_sort_spec->{$_}->{title} ) } keys %column_defs; $report->set_options( std_column_visibility => 1, controller_class => 'RequirementSpec', output_format => 'HTML', raw_top_info_text => $self->render('requirement_spec/report_top', { output => 0 }, is_template => $is_template), - raw_bottom_info_text => $self->render('requirement_spec/report_bottom', { output => 0 }), + raw_bottom_info_text => $self->render('requirement_spec/report_bottom', { output => 0 }, models => $self->models), title => $is_template ? t8('Requirement Spec Templates') : t8('Requirement Specs'), allow_pdf_export => 1, allow_csv_export => 1, @@ -419,9 +425,7 @@ sub prepare_report { $report->set_column_order(@columns); $report->set_export_options(qw(list filter)); $report->set_options_from_form; - $self->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable); - - $self->disable_pagination if $report->{options}{output_format} =~ /^(pdf|csv)$/i; + $self->models->set_report_generator_sort_options(report => $report, sortable_columns => \@sortable); } sub invalidate_version { @@ -453,6 +457,18 @@ sub render_pasted_text_block { ->jstree->open_node( '#tree', "#tb-${front_back}"); } +sub set_default_filter_args { + my ($self) = @_; + + if (!$::form->{filter} && !$::form->{is_template}) { + $::form->{filter} = { + status_id => [ map { $_->{id} } grep { $_->name ne 'done' } @{ $self->statuses } ], + }; + } + + return 1; +} + sub render_pasted_section { my ($self, $item, $parent_id) = @_; @@ -496,4 +512,78 @@ sub prepare_pictures_for_printing { return @files; } +sub update_project_link_none_keep_existing { + my ($self, $action) = @_; + + $self->requirement_spec->update_attributes(project_id => undef) if $action eq 'none'; + $self->requirement_spec->update_attributes(project_id => $::form->{new_project_id}) if $action eq 'existing'; + + return $self->invalidate_version + ->replaceWith('#basic_settings', $self->render('requirement_spec/_show_basic_settings', { output => 0 })) + ->remove('#project_link_form') + ->flash('info', t8('The project link has been updated.')) + ->render($self); +} + +sub update_project_link_new { + my ($self) = @_; + + return $self->js + ->replaceWith('#project_link_form', $self->render('requirement_spec/_new_project_form', { output => 0 })) + ->render($self); +} + +sub update_project_link_create { + my ($self) = @_; + my $params = delete($::form->{project}) || {}; + my $project = SL::DB::Project->new( + %{ $params }, + valid => 1, + active => 1, + ); + + my @errors = $project->validate; + + return $self->js->error(@errors)->render($self) if @errors; + + my $db = $self->requirement_spec->db; + if (!$db->do_transaction(sub { + $project->save; + $self->requirement_spec->update_attributes(project_id => $project->id); + + })) { + $::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error); + return $self->js->error(t8('Saving failed. Error message from the database: #1', $db->error))->render($self); + } + + return $self->invalidate_version + ->replaceWith('#basic_settings', $self->render('requirement_spec/_show_basic_settings', { output => 0 })) + ->remove('#project_link_form') + ->flash('info', t8('The project has been created.')) + ->flash('info', t8('The project link has been updated.')) + ->render($self); +} + +sub init_models { + my ($self) = @_; + + SL::Controller::Helper::GetModels->new( + controller => $self, + sorted => { + _default => { + by => 'customer', + dir => 1, + }, + %sort_columns, + }, + query => [ + and => [ + working_copy_id => undef, + is_template => $::form->{is_template} ? 1 : 0, + ], + ], + with_objects => [ 'customer', 'type', 'status', 'project' ], + ); +} + 1;