Projekt

Allgemein

Profil

Herunterladen (11,5 KB) Statistiken
| Zweig: | Markierung: | Revision:
package SL::Controller::PartsGroup;

use strict;

use parent qw(SL::Controller::Base);

use SL::DB::PartsGroup;
use SL::Helper::Flash;
use SL::Locale::String;
use List::MoreUtils qw(any);

use Rose::Object::MakeMethods::Generic (
scalar => [ qw(partsgroup) ],
# 'scalar --get_set_init' => [ qw(defaults) ],
);

__PACKAGE__->run_before('check_auth');
__PACKAGE__->run_before('load_partsgroup', only => [ qw(edit update delete) ]);

sub check_auth {
$::auth->assert('config');
}

#
# actions
#

sub action_list {
my ($self, %params) = @_;

$self->setup_list_action_bar;
$self->render('partsgroup/list',
title => $::locale->text('Partsgroups'),
PARTSGROUPS => SL::DB::Manager::PartsGroup->get_hierarchy,
);
}

sub action_sort_roots {
my ($self) = @_;

# Only for sorting the root partsgroup, and adding new ones.
# The simple arrows don't work on the main hierarchy view, if all subgroups
# are also shown. You would need a proper drag&drop Module for this.

my @root_partsgroups = grep { $_->{level} == 0 } @{ SL::DB::Manager::PartsGroup->get_hierarchy };

$self->setup_show_sort_action_bar;
$self->render(
'partsgroup/sort_roots',
title => t8('Edit partsgroups'),
PARTSGROUPS => \@root_partsgroups,
);
}

sub action_new {
my ($self) = @_;

$self->partsgroup(SL::DB::PartsGroup->new());
$self->show_form(title => t8('Add partsgroup'));
}

sub action_edit {
my ($self) = @_;

$self->show_form(title => t8('Edit partsgroup'),
PARTSGROUPS => SL::DB::Manager::PartsGroup->get_hierarchy, # for dropsdown to move parts
PARTS => $self->partsgroup->parts,
);
}

sub action_create {
my ($self) = @_;

$self->partsgroup(SL::DB::PartsGroup->new());
$self->create_or_update;
}

sub action_update {
my ($self) = @_;

$self->create_or_update;
}

sub action_delete {
my ($self) = @_;

$self->partsgroup->db->with_transaction(sub {
$self->partsgroup->delete();
flash_later('info', $::locale->text('The partsgroup has been deleted.'));

1;
}) || flash_later('error', $::locale->text('The partsgroup is in use and cannot be deleted.'));

$self->redirect_to(action => 'list');
}

#
# ajax actions
#

sub action_reorder {
my ($self) = @_;

SL::DB::PartsGroup->reorder_list(@{ $::form->{partsgroup_id} || [] });

$self->render(\'', { type => 'json' });
}

sub action_add_partsgroup {
my ($self) = @_;

unless ( $::form->{partsgroup_name} ) {
return $self->js->flash('error', t8("The name must not be empty."))
->render;
};

# check that name doesn't already exist in this grouping, catch before db constraint
if ( SL::DB::Manager::PartsGroup->get_all_count(
where => [ parent_id => $::form->{parent_id} // undef,
partsgroup => $::form->{partsgroup_name},
]) ) {
return $self->js->flash('error', t8("A partsgroup with this name already exists."))
->focus('#new_partsgroup')
->render;
};

my %partsgroup_params = (
partsgroup => $::form->{partsgroup_name},
);

$partsgroup_params{parent_id} = $::form->{parent_id} if $::form->{parent_id};

my $new_partsgroup = SL::DB::PartsGroup->new(%partsgroup_params);
$new_partsgroup->add_to_list(position => 'last');

$self->_render_subgroups_table_body;
return $self->js->val('#new_partsgroup', '')
->flash('info', t8("Added partsgroup."))
->focus('#new_partsgroup')
->render;
}


sub action_add_part {
my ($self) = @_;

$main::lxdebug->dump(0, "add_part form", $::form );

return $self->js->flash('error', t8("No part was selected."))->render
unless $::form->{part_id};

my $number_of_updated_parts = SL::DB::Manager::Part->update_all (
set => { partsgroup_id => $::form->{partsgroup_id} },
where => [ id => $::form->{part_id},
'!partsgroup_id' => $::form->{partsgroup_id}, # ignore updating to same partsgroup_id
]
);

if ( $number_of_updated_parts == 1 ) {
$self->_render_parts_table_body; # needs $::form->{partsgroup_id}
return $self->js->val('#add_part_id', undef)
->val('#add_part_id_name', '')
->flash('info', t8("Added part to partsgroup."))
->render;
} else {
return $self->js->flash('error', t8("Part wasn't added to partsgroup!"))->render;
}
}

sub action_update_partsgroup_for_parts{
my ($self) = @_;

$main::lxdebug->dump(0, "update_partsgroup", $::form );

# change type and design of existing parts to an existing part_variant
# updates part_variant_map entries and lemper_part.type_id and lemper_part.design

# the id of the partsgroup we are moving parts from is $::form->{current_partsgroup_id}

return $self->js->flash('error', t8("No parts selected."))->render unless $::form->{part_ids};
return $self->js->flash('error', t8("No partsgroup selected."))->render unless $::form->{selected_partsgroup_id};

# don't delete partsgroup ids from form, needed by _render_parts_table_body
# TODO: better error handling than die, use flash?
my $partsgroup = SL::DB::Manager::PartsGroup->find_by( id => $::form->{selected_partsgroup_id} ) // die 'selected partsgroup id not valid';
my $current_partsgroup = SL::DB::Manager::PartsGroup->find_by( id => $::form->{current_partsgroup_id} ) // die 'not a valid partsgroup id';

my $part_ids = $::form->{part_ids} // undef;
if ( scalar @{ $part_ids } ) {
my $parts_updated_count = 0;
$current_partsgroup->db->with_transaction(sub {
$parts_updated_count = SL::DB::Manager::Part->update_all (
set => { partsgroup_id => $partsgroup->id },
where => [ id => $part_ids,
# partsgroup_id => $current_partsgroup->id
], # what if one of them has changed in the meantime due to concurrent edits? should it fail? Currently
);
1;
}) or return $self->js->error(t8('The parts couldn\'t be updated!') . ' ' . $current_partsgroup->db->error )->render;
if ( $parts_updated_count == 1 ) {
$self->js->flash('info', t8("Moved #1 part.", $parts_updated_count));
} else {
$self->js->flash('info', t8("Moved #1 parts.", $parts_updated_count));
}
} else {
$self->js->flash('error', t8("No parts selected"));
}

$self->_render_parts_table_body; # needs $::form->{current_partsgroup_id}
return $self->js->render;
}

#
# action bars
#

sub setup_show_form_action_bar {
my ($self) = @_;

my $is_new = !$self->partsgroup->id;

for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
action => [
t8('Save'),
submit => [ '#form', { action => 'PartsGroup/' . ($is_new ? 'create' : 'update') } ],
checks => [ 'kivi.validate_form' ],
accesskey => 'enter',
],

action => [
t8('Delete'),
submit => [ '#form', { action => 'PartsGroup/delete' } ],
confirm => t8('Do you really want to delete this partsgroup?'),
disabled => $is_new ? t8('This partsgroup has not been saved yet.')
: !$self->partsgroup->orphaned ? t8('The partsgroup is in use and cannot be deleted.')
: undef,
],

link => [
t8('Abort'),
link => $self->url_for(action => 'list'),
],
);
}
$::request->layout->add_javascripts('kivi.Validator.js');
}

sub setup_list_action_bar {
my ($self) = @_;

for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
link => [
t8('Add'),
link => $self->url_for(action => 'new'),
],
link => [
t8('Sort'),
link => $self->url_for(action => 'sort_roots'),
],
);
}
}

sub setup_show_sort_action_bar {
my ($self) = @_;

for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
link => [
t8('Partsgroups'),
link => $self->url_for(action => 'list'),
],
);
}
}
#
# helpers
#

sub _render_subgroups_table_body {
my ($self) = @_;

my ($partsgroup, $partsgroups);
if ( $::form->{parent_id} ) {
$partsgroup = SL::DB::PartsGroup->new(id => $::form->{parent_id})->load;
$partsgroups = $partsgroup->children_sorted;
} else {
$partsgroups = SL::DB::Manager::PartsGroup->get_all(where => [ parent_id => undef ], sort_by => ('sortkey'));
$main::lxdebug->message(0, "found " . scalar @{ $partsgroups } . " roots");
}

my $html = $self->render('partsgroup/_subgroups_table_body', { output => 0 }, CHILDREN => $partsgroups);

$self->js->html('#subgroups_table_body', $html);
}


sub _render_parts_table_body {
my ($self) = @_;

# May be called when items are added to the current partsgroup
# (action_add_part with $::form->{partsgroup_id}
# or after items are moved away to other partsgroups
# (action_update_partsgroup_for_parts with $::form->{current_partsgroup_id})
my $parts = SL::DB::Manager::Part->get_all(
where => [ partsgroup_id => $::form->{current_partsgroup_id}
// $::form->{partsgroup_id}
]
);
my $html = $self->render('partsgroup/_parts_table_body', { output => 0 }, PARTS => $parts);
$self->js->html('#parts_table_body', $html);
}

sub create_or_update {
my ($self) = @_;
my $is_new = !$self->partsgroup->id;

my $params = delete($::form->{partsgroup}) || { };

delete $params->{id};

# parent_id needs additional checks
# If the parent_id was changed the new parent_id mustn't have the current
# parent_id as its ancestor, otherwise this would introdouce cycles in the
# tree.
# run this to prevent $params->{parent_id} to be used for assign_attributes

my $old_parent_id = $self->partsgroup->parent_id; # may be undef
my $new_parent_id = delete $params->{parent_id} || undef; # empty string/select will become undef

my @errors;

my $db = $self->partsgroup->db;
if (!$db->with_transaction(sub {

# assign attributes and validate
$self->partsgroup->assign_attributes( %{$params} ) ;
push(@errors, $self->partsgroup->validate); # check for description

if (@errors) {
die @errors . "\n";
};

if ( ( $old_parent_id == $new_parent_id )
or ( !defined $old_parent_id && ! defined $new_parent_id )
) {
# parent_id didn't change
$self->partsgroup->save;

} elsif ( ( $old_parent_id != $new_parent_id )
or ( not defined $old_parent_id && $new_parent_id )
or ( $old_parent_id && not defined $new_parent_id) # setting parent to undef is always allowed!
) {
# parent_id has changed, check for cycles
my $ancestor_ids = SL::DB::PartsGroup->new(id => $new_parent_id)->ancestor_ids;

if ( any { $self->partsgroup->id == $_ } @{$ancestor_ids} ) {
die "Error: This would introduce a cycle, new parent must not be a subparent\n";
};
$self->partsgroup->remove_from_list;
$self->partsgroup->parent_id($new_parent_id);
$self->partsgroup->add_to_list(position => 'last');
}

1;
})) {
die @errors ? join("\n", @errors) . "\n" : $db->error . "\n";
}

flash_later('info', $is_new ? t8('The partsgroup has been created.') : t8('The partsgroup has been saved.'));
$self->redirect_to(action => 'list');
}

sub show_form {
my ($self, %params) = @_;

$self->setup_show_form_action_bar;
$self->render('partsgroup/form', %params,
);
}

sub load_partsgroup {
my ($self) = @_;

$self->partsgroup(SL::DB::PartsGroup->new(id => $::form->{id})->load);
}

1;
(49-49/86)