|
package SL::Controller::Part;
|
|
|
|
use strict;
|
|
use parent qw(SL::Controller::Base);
|
|
|
|
use Carp;
|
|
use Clone qw(clone);
|
|
use Data::Dumper;
|
|
use DateTime;
|
|
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;
|
|
|
|
use SL::CVar;
|
|
use SL::Controller::Helper::GetModels;
|
|
use SL::DB::Business;
|
|
use SL::DB::BusinessModel;
|
|
use SL::DB::Helper::ValidateAssembly qw(validate_assembly);
|
|
use SL::DB::History;
|
|
use SL::DB::Part;
|
|
use SL::DB::PartsGroup;
|
|
use SL::DB::PriceRuleItem;
|
|
use SL::DB::PurchaseBasketItem;
|
|
use SL::DB::Shop;
|
|
use SL::DB::VariantProperty;
|
|
use SL::DB::VariantPropertyPart;
|
|
use SL::DB::VariantPropertyValuePart;
|
|
use SL::Helper::Flash;
|
|
use SL::Helper::PrintOptions;
|
|
use SL::JSON;
|
|
use SL::Locale::String qw(t8);
|
|
use SL::MoreCommon qw(save_form);
|
|
use SL::Presenter;
|
|
use SL::Presenter::EscapedText qw(escape is_escaped);
|
|
use SL::Presenter::Part;
|
|
use SL::Presenter::Tag qw(select_tag);
|
|
|
|
use Rose::Object::MakeMethods::Generic (
|
|
'scalar --get_set_init' => [ qw(parts models part p warehouses multi_items_models
|
|
makemodels businessmodels shops_not_assigned
|
|
customerprices
|
|
orphaned
|
|
assortment assortment_items assembly assembly_items
|
|
all_pricegroups all_translations all_partsgroups all_units
|
|
all_buchungsgruppen all_payment_terms all_warehouses
|
|
parts_classification_filter
|
|
all_languages all_units all_price_factors
|
|
all_businesses) ],
|
|
'scalar' => [ qw(warehouse bin stock_amounts journal) ],
|
|
);
|
|
|
|
# safety
|
|
__PACKAGE__->run_before(sub { $::auth->assert('part_service_assembly_edit', 1) || $::auth->assert('part_service_assembly_details') },
|
|
except => [ qw(ajax_autocomplete part_picker_search part_picker_result) ]);
|
|
|
|
__PACKAGE__->run_before(sub { $::auth->assert('developer') },
|
|
only => [ qw(test_page) ]);
|
|
|
|
__PACKAGE__->run_before('check_part_id', only => [ qw(edit delete) ]);
|
|
|
|
# actions for editing parts
|
|
#
|
|
sub action_add_part {
|
|
my ($self, %params) = @_;
|
|
|
|
$self->part( SL::DB::Part->new_part );
|
|
$self->add;
|
|
};
|
|
|
|
sub action_add_service {
|
|
my ($self, %params) = @_;
|
|
|
|
$self->part( SL::DB::Part->new_service );
|
|
$self->add;
|
|
};
|
|
|
|
sub action_add_assembly {
|
|
my ($self, %params) = @_;
|
|
|
|
$self->part( SL::DB::Part->new_assembly );
|
|
$self->add;
|
|
};
|
|
|
|
sub action_add_assortment {
|
|
my ($self, %params) = @_;
|
|
|
|
$self->part( SL::DB::Part->new_assortment );
|
|
$self->add;
|
|
};
|
|
|
|
sub action_add_parent_variant {
|
|
my ($self, %params) = @_;
|
|
|
|
$self->part( SL::DB::Part->new_parent_variant );
|
|
$self->part->part_type($::form->{part_type});
|
|
$self->add;
|
|
}
|
|
|
|
sub action_add_from_record {
|
|
my ($self) = @_;
|
|
|
|
check_has_valid_part_type($::form->{part}{part_type});
|
|
|
|
die 'parts_classification_type must be "sales" or "purchases"'
|
|
unless $::form->{parts_classification_type} =~ m/^(sales|purchases)$/;
|
|
|
|
$self->parse_form;
|
|
$self->add;
|
|
}
|
|
|
|
sub action_add {
|
|
my ($self) = @_;
|
|
|
|
check_has_valid_part_type($::form->{part_type});
|
|
|
|
$self->action_add_part if $::form->{part_type} eq 'part';
|
|
$self->action_add_service if $::form->{part_type} eq 'service';
|
|
$self->action_add_assembly if $::form->{part_type} eq 'assembly';
|
|
$self->action_add_assortment if $::form->{part_type} eq 'assortment';
|
|
};
|
|
|
|
sub action_save {
|
|
my ($self, %params) = @_;
|
|
|
|
# checks that depend only on submitted $::form
|
|
$self->check_form or return $self->js->render;
|
|
|
|
my $is_new = !$self->part->id; # $ part gets loaded here
|
|
|
|
# check that the part hasn't been modified
|
|
unless ( $is_new ) {
|
|
$self->check_part_not_modified or
|
|
return $self->js->error(t8('The document has been changed by another user. Please reopen it in another window and copy the changes to the new window'))->render;
|
|
}
|
|
|
|
if ( $is_new
|
|
&& $::form->{part}{partnumber}
|
|
&& SL::DB::Manager::Part->find_by(partnumber => $::form->{part}{partnumber})
|
|
) {
|
|
return $self->js->error(t8('The partnumber is already being used'))->render;
|
|
}
|
|
|
|
$self->parse_form;
|
|
|
|
my @errors = $self->part->validate;
|
|
return $self->js->error(@errors)->render if @errors;
|
|
|
|
if ($is_new) {
|
|
# Ensure CVars that should be enabled by default actually are when
|
|
# creating new parts.
|
|
my @default_valid_configs =
|
|
grep { ! $_->{flag_defaults_to_invalid} }
|
|
grep { $_->{module} eq 'IC' }
|
|
@{ CVar->get_configs() };
|
|
|
|
$::form->{"cvar_" . $_->{name} . "_valid"} = 1 for @default_valid_configs;
|
|
} else {
|
|
$self->{lastcost_modified} = $self->check_lastcost_modified;
|
|
}
|
|
|
|
# $self->part has been loaded, parsed and validated without errors and is ready to be saved
|
|
$self->part->db->with_transaction(sub {
|
|
|
|
$self->part->save(cascade => 1);
|
|
$self->part->set_lastcost_assemblies_and_assortiments if $self->{lastcost_modified};
|
|
|
|
SL::DB::History->new(
|
|
trans_id => $self->part->id,
|
|
snumbers => 'partnumber_' . $self->part->partnumber,
|
|
employee_id => SL::DB::Manager::Employee->current->id,
|
|
what_done => 'part',
|
|
addition => 'SAVED',
|
|
)->save();
|
|
|
|
CVar->save_custom_variables(
|
|
dbh => |