Projekt

Allgemein

Profil

Herunterladen (123 KB) Statistiken
| Zweig: | Markierung: | Revision:
package SL::Controller::Order;

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

use SL::Helper::Flash qw(flash_later);
use SL::HTML::Util;
use SL::Presenter::Tag qw(select_tag hidden_tag div_tag);
use SL::Locale::String qw(t8);
use SL::SessionFile::Random;
use SL::IMAPClient;
use SL::PriceSource;
use SL::Webdav;
use SL::File;
use SL::MIME;
use SL::Util qw(trim);
use SL::YAML;
use SL::DB::AdditionalBillingAddress;
use SL::DB::AuthUser;
use SL::DB::History;
use SL::DB::Order;
use SL::DB::Default;
use SL::DB::Unit;
use SL::DB::Part;
use SL::DB::PartClassification;
use SL::DB::PartsGroup;
use SL::DB::Printer;
use SL::DB::Note;
use SL::DB::Language;
use SL::DB::Reclamation;
use SL::DB::RecordLink;
use SL::DB::RequirementSpec;
use SL::DB::Shipto;
use SL::DB::Translation;
use SL::DB::ValidityToken;
use SL::Model::Record;

use SL::Helper::CreatePDF qw(:all);
use SL::Helper::PrintOptions;
use SL::Helper::ShippedQty;
use SL::Helper::UserPreferences::DisplayPreferences;
use SL::Helper::UserPreferences::PositionsScrollbar;
use SL::Helper::UserPreferences::UpdatePositions;

use SL::Controller::Helper::GetModels;

use List::Util qw(first sum0);
use List::UtilsBy qw(sort_by uniq_by);
use List::MoreUtils qw(uniq any none pairwise first_index);
use English qw(-no_match_vars);
use File::Spec;
use Cwd;
use Sort::Naturally;

use Rose::Object::MakeMethods::Generic
(
scalar => [ qw(item_ids_to_delete is_custom_shipto_to_delete) ],
'scalar --get_set_init' => [ qw(order valid_types type cv p all_price_factors
search_cvpartnumber show_update_button
part_picker_classification_ids
is_final_version) ],
);


# safety
__PACKAGE__->run_before('check_auth',
except => [ qw(close_quotations) ]);

__PACKAGE__->run_before('check_auth_for_edit',
except => [ qw(edit show_customer_vendor_details_dialog price_popup load_second_rows close_quotations) ]);

#
# actions
#

# add a new order
sub action_add {
my ($self) = @_;

$self->order->transdate(DateTime->now_local());
my $extra_days = $self->type eq sales_quotation_type() ? $::instance_conf->get_reqdate_interval :
$self->type eq sales_order_type() ? $::instance_conf->get_delivery_date_interval :
$self->type eq sales_order_intake_type() ? $::instance_conf->get_delivery_date_interval : 1;

if (($self->type eq sales_order_intake_type() && $::instance_conf->get_deliverydate_on)
|| ($self->type eq sales_order_type() && $::instance_conf->get_deliverydate_on)
|| ($self->type eq sales_quotation_type() && $::instance_conf->get_reqdate_on)
&& (!$self->order->reqdate)) {
$self->order->reqdate(DateTime->today_local->next_workday(extra_days => $extra_days));
}


$self->pre_render();

if (!$::form->{form_validity_token}) {
$::form->{form_validity_token} = SL::DB::ValidityToken->create(scope => SL::DB::ValidityToken::SCOPE_ORDER_SAVE())->token;
}

$self->render(
'order/form',
title => $self->get_title_for('add'),
%{$self->{template_args}}
);
}

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

my $reclamation = SL::DB::Reclamation->new(id => $::form->{from_id})->load;
my %params;
my $target_type = $reclamation->is_sales ? 'sales_order'
: 'purchase_order';
my $order = SL::Model::Record->new_from_workflow($reclamation, $target_type);
$self->{converted_from_reclamation_id} = $::form->{from_id};

$self->order($order);

$self->recalc();
$self->pre_render();

if (!$::form->{form_validity_token}) {
$::form->{form_validity_token} = SL::DB::ValidityToken->create(scope => SL::DB::ValidityToken::SCOPE_ORDER_SAVE())->token;
}

$self->render(
'order/form',
title => $self->get_title_for('edit'),
%{$self->{template_args}}
);
}

# edit an existing order
sub action_edit {
my ($self) = @_;

if ($::form->{id}) {
$self->load_order;

if ($self->order->is_sales) {
my $imap_client = SL::IMAPClient->new();
if ($imap_client) {
$imap_client->update_email_files_for_record($self->order);
}
}

} else {
# this is to edit an order from an unsaved order object

# set item ids to new fake id, to identify them as new items
foreach my $item (@{$self->order->items_sorted}) {
$item->{new_fake_id} = join('_', 'new', Time::HiRes::gettimeofday(), int rand 1000000000000);
}
# trigger rendering values for second row as hidden, because they
# are loaded only on demand. So we need to keep the values from
# the source.
$_->{render_second_row} = 1 for @{ $self->order->items_sorted };

if (!$::form->{form_validity_token}) {
$::form->{form_validity_token} = SL::DB::ValidityToken->create(scope => SL::DB::ValidityToken::SCOPE_ORDER_SAVE())->token;
}
}

$self->recalc();
$self->pre_render();
$self->render(
'order/form',
title => $self->get_title_for('edit'),
%{$self->{template_args}}
);
}

# edit a collective order (consisting of one or more existing orders)
sub action_edit_collective {
my ($self) = @_;

# collect order ids
my @multi_ids = map {
$_ =~ m{^multi_id_(\d+)$} && $::form->{'multi_id_' . $1} && $::form->{'trans_id_' . $1} && $::form->{'trans_id_' . $1}
} grep { $_ =~ m{^multi_id_\d+$} } keys %$::form;

# fall back to add if no ids are given
if (scalar @multi_ids == 0) {
$self->action_add();
return;
}

# fall back to save as new if only one id is given
if (scalar @multi_ids == 1) {
$self->order(SL::DB::Order->new(id => $multi_ids[0])->load);
$self->action_save_as_new();
return;
}

# make new order from given orders
my @multi_orders = map { SL::DB::Order->new(id => $_)->load } @multi_ids;
$self->{converted_from_oe_id} = join ' ', map { $_->id } @multi_orders;
my $target_type = "sales_order";
my $order = SL::Model::Record->new_from_workflow_multi(\@multi_orders, $target_type, sort_sources_by => 'transdate');
$self->order($order);

$self->action_edit();
}

# delete the order
sub action_delete {
my ($self) = @_;

my $errors = $self->delete();

if (scalar @{ $errors }) {
$self->js->flash('error', $_) foreach @{ $errors };
return $self->js->render();
}

my $text = $self->type eq sales_order_intake_type() ? $::locale->text('The order intake has been deleted')
: $self->type eq sales_order_type() ? $::locale->text('The order confirmation has been deleted')
: $self->type eq purchase_order_type() ? $::locale->text('The order has been deleted')
: $self->type eq sales_quotation_type() ? $::locale->text('The quotation has been deleted')
: $self->type eq request_quotation_type() ? $::locale->text('The rfq has been deleted')
: $self->type eq purchase_quotation_intake_type() ? $::locale->text('The quotation intake has been deleted')
: '';
flash_later('info', $text);

my @redirect_params = (
action => 'add',
type => $self->type,
);

$self->redirect_to(@redirect_params);
}

# save the order
sub action_save {
my ($self) = @_;

my $errors = $self->save();

if (scalar @{ $errors }) {
$self->js->flash('error', $_) foreach @{ $errors };
return $self->js->render();
}

my $text = $self->type eq sales_order_intake_type() ? $::locale->text('The order intake has been saved')
: $self->type eq sales_order_type() ? $::locale->text('The order confirmation has been saved')
: $self->type eq purchase_order_type() ? $::locale->text('The order has been saved')
: $self->type eq sales_quotation_type() ? $::locale->text('The quotation has been saved')
: $self->type eq request_quotation_type() ? $::locale->text('The rfq has been saved')
sub action_save_and_invoice_for_advance_payment {
my ($self) = @_;

$self->save_and_redirect_to(
controller => 'oe.pl',
action => 'oe_invoice_from_order',
new_invoice_type => 'invoice_for_advance_payment',
);
}

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

$self->save_and_redirect_to(
controller => 'oe.pl',
action => '