Revision 706e28ed
Von Tamino Steinert vor etwa 1 Jahr hinzugefügt
| SL/Controller/Part.pm | ||
|---|---|---|
|
use File::Temp;
|
||
|
use List::Util qw(sum);
|
||
|
use List::UtilsBy qw(extract_by);
|
||
|
use List::MoreUtils qw(any pairwise);
|
||
|
use POSIX qw(strftime);
|
||
|
use Text::CSV_XS;
|
||
|
|
||
| ... | ... | |
|
|
||
|
my $part = $self->part;
|
||
|
my $variant_properties = $part->variant_properties();
|
||
|
my @needed_variant_property_ids = sort map {$_->id} @$variant_properties;
|
||
|
|
||
|
if (@variant_property_ids != @needed_variant_property_ids) {
|
||
|
if (any {$_} grep {
|
||
|
!defined $::form->{variant_properties}->{$_->id}->{selected_property_value_ids}
|
||
|
} @$variant_properties
|
||
|
) {
|
||
|
return $self->js->error(
|
||
|
t8('No property value selected for variant properties: #1.',
|
||
|
join(", ",
|
||
|
map {$_->displayable_name}
|
||
|
grep {!defined $::form->{variant_properties}->{$_->id}->{selected_property_values}}
|
||
|
grep {!defined $::form->{variant_properties}->{$_->id}->{selected_property_value_ids}}
|
||
|
@$variant_properties
|
||
|
)
|
||
|
)
|
||
| ... | ... | |
|
my @grouped_variant_property_values = ();
|
||
|
push @grouped_variant_property_values,
|
||
|
SL::DB::Manager::VariantPropertyValue->get_all(
|
||
|
where => [ id => $::form->{variant_properties}->{$_}->{selected_property_values} ]
|
||
|
where => [ id => $::form->{variant_properties}->{$_}->{selected_property_value_ids} ]
|
||
|
)
|
||
|
for @variant_property_ids;
|
||
|
|
||
|
|
||
|
my @variant_property_values_lists = ();
|
||
|
my @variant_property_value_lists = ();
|
||
|
foreach my $variant_property_values (@grouped_variant_property_values) {
|
||
|
my @new_lists = ();
|
||
|
foreach my $variant_property_value (@$variant_property_values) {
|
||
|
unless (scalar @variant_property_values_lists) {
|
||
|
unless (scalar @variant_property_value_lists) {
|
||
|
push @new_lists, [$variant_property_value];
|
||
|
}
|
||
|
foreach my $variant_property_values_list (@variant_property_values_lists) {
|
||
|
foreach my $variant_property_values_list (@variant_property_value_lists) {
|
||
|
push @new_lists, [@$variant_property_values_list, $variant_property_value];
|
||
|
}
|
||
|
}
|
||
|
@variant_property_values_lists = @new_lists;
|
||
|
@variant_property_value_lists = @new_lists;
|
||
|
}
|
||
|
|
||
|
my @new_variants = ();
|
||
|
_check_variant_property_values_not_taken($part, \@variant_property_value_lists);
|
||
|
SL::DB->client->with_transaction(sub {
|
||
|
push @new_variants, $part->create_new_variant($_)
|
||
|
for @variant_property_values_lists;
|
||
|
$part->create_new_variant($_) for @variant_property_value_lists;
|
||
|
1;
|
||
|
}) or do {
|
||
|
die t8('Error while creating variants: '), $@;
|
||
|
die t8('Error while creating variants: '), SL::DB->client->error;
|
||
|
};
|
||
|
|
||
|
$self->redirect_to(
|
||
|
controller => 'Part',
|
||
|
action => 'edit',
|
||
|
'part.id' => $self->part->id
|
||
|
);
|
||
|
}
|
||
|
|
||
|
sub action_convert_part_to_variant {
|
||
|
my ($self) = @_;
|
||
|
|
||
|
my $convert_part_id = $::form->{convert_part}->{id};
|
||
|
die t8("Please select a part to convert.") unless $convert_part_id;
|
||
|
|
||
|
my @variant_property_ids = sort keys %{$::form->{convert_part}->{variant_properties}};
|
||
|
|
||
|
my $part = $self->part;
|
||
|
my $variant_properties = $part->variant_properties();
|
||
|
my @needed_variant_property_ids = sort map {$_->id} @$variant_properties;
|
||
|
|
||
|
if (@variant_property_ids != @needed_variant_property_ids) {
|
||
|
return $self->js->error(
|
||
|
t8('No property value selected for variant properties: #1.',
|
||
|
join(", ",
|
||
|
map {$_->displayable_name}
|
||
|
grep {!defined $::form->{convert_part}->{variant_properties}->{$_->id}->{selected_property_value_id}}
|
||
|
@$variant_properties
|
||
|
)
|
||
|
)
|
||
|
)->render();
|
||
|
}
|
||
|
|
||
|
my @variant_property_values = map {
|
||
|
SL::DB::VariantPropertyValue->new(
|
||
|
id => $::form->{convert_part}->{variant_properties}->{$_}->{selected_property_value_id}
|
||
|
)->load()
|
||
|
} @variant_property_ids;
|
||
|
|
||
|
_check_variant_property_values_not_taken($part, [\@variant_property_values]);
|
||
|
SL::DB->client->with_transaction(sub {
|
||
|
my $part_to_convert = SL::DB::Part->new(id => $convert_part_id)->load;
|
||
|
$part_to_convert->variant_type('variant');
|
||
|
$part_to_convert->variant_property_values(\@variant_property_values);
|
||
|
$part_to_convert->parent_variant($part);
|
||
|
$part_to_convert->save;
|
||
|
1;
|
||
|
}) or do {
|
||
|
die t8('Error while converting part to variant: '), SL::DB->Client->error;
|
||
|
};
|
||
|
|
||
|
$self->redirect_to(
|
||
| ... | ... | |
|
Carp::confess "invalid part_type" unless $_[0] =~ /^(part|service|assembly|assortment)$/;
|
||
|
}
|
||
|
|
||
|
sub _check_variant_property_values_not_taken {
|
||
|
my ($parent_variant, $variant_property_value_lists) = @_;
|
||
|
|
||
|
my @double_lists;
|
||
|
my $variants = $parent_variant->variants;
|
||
|
foreach my $variant (@$variants) {
|
||
|
my @property_value_ids = sort map {$_->id} $variant->variant_property_values;
|
||
|
foreach my $test_property_values (@$variant_property_value_lists) {
|
||
|
my @test_property_value_ids = sort map {$_->id} @$test_property_values;
|
||
|
if (@test_property_value_ids == @property_value_ids
|
||
|
&& not any {$_} pairwise {$a != $b} @test_property_value_ids, @property_value_ids
|
||
|
) {
|
||
|
push @double_lists, join(', ', map {$_->displayable_name} @$test_property_values);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (@double_lists) {
|
||
|
die t8("There is already a variant with the property values: #1.", join("; ", @double_lists));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sub normalize_text_blocks {
|
||
|
my ($self) = @_;
|
||
| SL/DB/Part.pm | ||
|---|---|---|
|
use strict;
|
||
|
|
||
|
use Carp;
|
||
|
use List::MoreUtils qw(any uniq);
|
||
|
use List::MoreUtils qw(any uniq pairwise);
|
||
|
use List::Util qw(sum max);
|
||
|
use Rose::DB::Object::Helpers qw(as_tree);
|
||
|
|
||
| ... | ... | |
|
|
||
|
__PACKAGE__->before_save('_before_save_set_partnumber');
|
||
|
__PACKAGE__->before_save('_before_save_set_assembly_weight');
|
||
|
__PACKAGE__->before_save('_before_check_variant_property_values');
|
||
|
|
||
|
sub _before_save_set_partnumber {
|
||
|
my ($self) = @_;
|
||
| ... | ... | |
|
return 1;
|
||
|
}
|
||
|
|
||
|
sub _before_check_variant_property_values {
|
||
|
my ($self) = @_;
|
||
|
if ($self->is_variant) {
|
||
|
my @property_value_ids = sort map {$_->id} $self->variant_property_values;
|
||
|
my ($parent_variant) = $self->parent_variant;
|
||
|
my $other_variants = $parent_variant->variants;
|
||
|
foreach my $variant (@$other_variants) {
|
||
|
next if $variant->id == $self->id;
|
||
|
my @other_property_value_ids = sort map {$_->id} $variant->variant_property_values;
|
||
|
if (@other_property_value_ids == @property_value_ids
|
||
|
&& not any {$_} pairwise {$a != $b} @other_property_value_ids, @property_value_ids
|
||
|
) {
|
||
|
die t8("There is already a variant with the property values: "),
|
||
|
join(' ,', map {$_->displayable_name} $self->variant_property_values);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
sub items {
|
||
|
my ($self) = @_;
|
||
|
|
||
| ... | ... | |
|
die "Given variant_property_values dosn't match the variant_properties of parent_variant part";
|
||
|
}
|
||
|
|
||
|
my $separator = '.'; # TODO: make configurable
|
||
|
my $new_variant = $self->clone_and_reset;
|
||
|
$new_variant->partnumber($self->_next_variant_partnumber);
|
||
|
$new_variant->variant_type('variant');
|
||
|
$new_variant->add_assemblies(map {$_->clone_and_reset} $self->assemblies) if ($self->is_assembly);
|
||
|
$new_variant->add_variant_property_values(@$variant_property_values);
|
||
|
$new_variant->parent_variant($self);
|
||
|
$new_variant->save;
|
||
|
|
||
|
$self->add_variants($new_variant);
|
||
|
return $new_variant;
|
||
|
}
|
||
|
|
||
|
sub _next_variant_partnumber {
|
||
|
my ($self) = @_;
|
||
|
die "only callable on parts of type parent_variant" unless $self->is_parent_variant;
|
||
|
|
||
|
my $separator = '.'; # TODO: make configurable
|
||
|
my $last_variant_number =
|
||
|
max
|
||
|
map {
|
||
| ... | ... | |
|
}
|
||
|
$self->variants;
|
||
|
|
||
|
my $new_variant = $self->clone_and_reset;
|
||
|
$new_variant->partnumber($self->partnumber . $separator . ($last_variant_number + 1));
|
||
|
$new_variant->variant_type('variant');
|
||
|
$new_variant->add_assemblies(map {$_->clone_and_reset} $self->assemblies) if ($self->is_assembly);
|
||
|
$new_variant->add_variant_property_values(@$variant_property_values);
|
||
|
|
||
|
$self->add_variants($new_variant);
|
||
|
$self->save;
|
||
|
return $new_variant;
|
||
|
return $self->partnumber . $separator . ($last_variant_number + 1);
|
||
|
}
|
||
|
|
||
|
sub clone_and_reset_deep {
|
||
| SL/Presenter/Part.pm | ||
|---|---|---|
|
for autocompletion. You may comma separate multiple types as in
|
||
|
C<part,assembly>.
|
||
|
|
||
|
If C<%params> contains C<variant_type> only parts of this variant type will be
|
||
|
used for autocompletion. You may comma separate multiple variant types as in
|
||
|
C<single,variant>.
|
||
|
|
||
|
If C<%params> contains C<status> only parts of this status will be used
|
||
|
for autocompletion. C<status> can be one of the following strings:
|
||
|
C<active>, C<obsolete> or C<all>. C<active> is the default if C<status> is
|
||
| js/kivi.Part.js | ||
|---|---|---|
|
$.post("controller.pl", data, kivi.eval_json_result);
|
||
|
};
|
||
|
|
||
|
ns.convert_part_to_variant = function() {
|
||
|
var data = $('#ic').serializeArray();
|
||
|
data.push({ name: 'action', value: 'Part/convert_part_to_variant' });
|
||
|
$.post("controller.pl", data, kivi.eval_json_result);
|
||
|
};
|
||
|
|
||
|
ns.update_variant_property_value_options = function() {
|
||
|
var data = $('#ic').serializeArray();
|
||
|
data.push({ name: 'action', value: 'Part/update_variant_property_value_options' });
|
||
| ... | ... | |
|
if (this.o.part_type)
|
||
|
data['filter.part_type'] = this.o.part_type.split(',');
|
||
|
|
||
|
if (this.o.variant_type)
|
||
|
data['filter.variant_type'] = this.o.variant_type.split(',');
|
||
|
|
||
|
if (this.o.status) {
|
||
|
if (this.o.status == 'active') data['filter.obsolete'] = 0;
|
||
|
if (this.o.status == 'obsolete') data['filter.obsolete'] = 1;
|
||
| templates/design40_webpages/part/_parent_variant.html | ||
|---|---|---|
|
<div class="wrapper">
|
||
|
[% FOREACH variant_property = SELF.part.variant_properties %]
|
||
|
<div class="col input-panel" style="min-width:fit-content;">
|
||
|
<h4>[% variant_property.name_translated | html %]</h4>
|
||
|
[% L.select_tag("variant_properties." _ variant_property.id _ ".selected_property_values[]",
|
||
|
<h4>[% variant_property.displayable_name | html %]</h4>
|
||
|
[% L.select_tag("variant_properties." _ variant_property.id _ ".selected_property_value_ids[]",
|
||
|
variant_property.property_values,
|
||
|
title_key='displayable_name', value_key='id',
|
||
|
id="selected_property_values_" _ variant_property.id,
|
||
|
id="selected_property_value_ids_" _ variant_property.id,
|
||
|
multiple=1,
|
||
|
) %]
|
||
|
[% L.multiselect2side(
|
||
|
"selected_property_values_" _ variant_property.id,
|
||
|
"selected_property_value_ids_" _ variant_property.id,
|
||
|
labelsx=LxERP.t8("All Property Values"),
|
||
|
labeldx=LxERP.t8("Selected Property Values")
|
||
|
) %]
|
||
| ... | ... | |
|
</div>
|
||
|
[% L.button_tag('kivi.Part.create_variants();', LxERP.t8("Create Variants with selected Values")) %]
|
||
|
</div>
|
||
|
|
||
|
<div class="wrapper input-panel">
|
||
|
<h3> [% LxERP.t8("Convert part to Variant") %] </h3>
|
||
|
<table class="tbl-list">
|
||
|
<caption>
|
||
|
[% 'Variant Properties' | $T8 %]
|
||
|
</caption>
|
||
|
<thead>
|
||
|
<tr>
|
||
|
<th>[% 'Name' | $T8 %]</th>
|
||
|
<th>[% 'Value' | $T8 %]</th>
|
||
|
</tr>
|
||
|
</thead>
|
||
|
<tbody>
|
||
|
[% FOREACH variant_property = SELF.part.variant_properties %]
|
||
|
<tr>
|
||
|
<td>[% variant_property.displayable_name | html %]</td>
|
||
|
<td>
|
||
|
[% L.select_tag("convert_part.variant_properties." _ variant_property.id _ ".selected_property_value_id",
|
||
|
variant_property.property_values,
|
||
|
title_key='displayable_name', value_key='id',
|
||
|
size=variant_property.property_values.size,
|
||
|
) %]
|
||
|
</tr>
|
||
|
[% END %]
|
||
|
</tbody>
|
||
|
</table>
|
||
|
<label for="convert_part.id">[% 'Part to convert:' | $T8 %]</label>
|
||
|
[% P.part.picker('convert_part.id', undef,
|
||
|
part_type=SELF.part.part_type, variant_type='single',
|
||
|
placeholder=(LxERP.t8('Type:') _ ' ' _ LxERP.t8(SELF.part.part_type)),
|
||
|
class="wi-wide"
|
||
|
) %]
|
||
|
<br>
|
||
|
<br>
|
||
|
[% L.button_tag('kivi.Part.convert_part_to_variant();', LxERP.t8("Convert")) %]
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
|
||
Auch abrufbar als: Unified diff
Varianten: einfachen Artikel in Variante umwandeln