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;
use Data::Dumper;
use DateTime;
use SL::DB::History;
+use SL::DB::Helper::ValidateAssembly qw(validate_assembly);
use SL::CVar;
use Carp;
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) ],
);
->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 {
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')
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')
->html('#items_lastcost_sum_basic', $::form->format_amount(\%::myconfig, $items_lastcost_sum, 2, 0))
->render;
}
+
sub action_add_assembly_item {
my ($self) = @_;
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++;
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;
}
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 {
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;
}
# 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);
}
}
}
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 {
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;
}
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;
partnumber => t8('Partnumber'),
description => t8('Description'),
},
- with_objects => [ qw(unit_obj) ],
+ with_objects => [ qw(unit_obj classification) ],
);
}
}
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 {
}
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 {
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 => {
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}
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')