|
package SL::Controller::DeliveryOrder;
|
|
|
|
use strict;
|
|
use parent qw(SL::Controller::Base);
|
|
|
|
use SL::Helper::Flash qw(flash_later);
|
|
use SL::Helper::Number qw(_format_number _parse_number);
|
|
use SL::Presenter::Tag qw(select_tag hidden_tag div_tag);
|
|
use SL::Presenter::DeliveryOrder qw(delivery_order_status_line);
|
|
use SL::Locale::String qw(t8);
|
|
use SL::SessionFile::Random;
|
|
use SL::PriceSource;
|
|
use SL::Webdav;
|
|
use SL::File;
|
|
use SL::MIME;
|
|
use SL::YAML;
|
|
use SL::DB::History;
|
|
use SL::DB::Order;
|
|
use SL::DB::Default;
|
|
use SL::DB::Unit;
|
|
use SL::DB::Order;
|
|
use SL::DB::Part;
|
|
use SL::DB::PartClassification;
|
|
use SL::DB::PartsGroup;
|
|
use SL::DB::Printer;
|
|
use SL::DB::Language;
|
|
use SL::DB::Reclamation;
|
|
use SL::DB::RecordLink;
|
|
use SL::DB::Shipto;
|
|
use SL::DB::Translation;
|
|
use SL::DB::TransferType;
|
|
use SL::DB::ValidityToken;
|
|
use SL::DB::Warehouse;
|
|
use SL::DB::Helper::RecordLink qw(set_record_link_conversions);
|
|
use SL::DB::Helper::TypeDataProxy;
|
|
use SL::DB::DeliveryOrder;
|
|
use SL::DB::DeliveryOrder::TypeData qw(:types);
|
|
use SL::DB::DeliveryOrderItemsStock;
|
|
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(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 type_data) ],
|
|
);
|
|
|
|
|
|
# safety
|
|
__PACKAGE__->run_before('check_auth',
|
|
except => [ qw(update_stock_information) ]);
|
|
|
|
__PACKAGE__->run_before('check_auth_for_edit',
|
|
except => [ qw(update_stock_information edit show_customer_vendor_details_dialog price_popup stock_in_out_dialog load_second_rows) ]);
|
|
|
|
__PACKAGE__->run_before('get_unalterable_data',
|
|
only => [ qw(save save_as_new save_and_delivery_order save_and_invoice save_and_ap_transaction
|
|
print send_email) ]);
|
|
|
|
#
|
|
# actions
|
|
#
|
|
|
|
# add a new order
|
|
sub action_add {
|
|
my ($self) = @_;
|
|
|
|
$self->order(SL::Model::Record->update_after_new($self->order, $self->type));
|
|
|
|
$self->pre_render();
|
|
|
|
if (!$::form->{form_validity_token}) {
|
|
$::form->{form_validity_token} = SL::DB::ValidityToken->create(scope => SL::DB::ValidityToken::SCOPE_DELIVERY_ORDER_SAVE())->token;
|
|
}
|
|
|
|
$self->render(
|
|
'delivery_order/form',
|
|
title => $self->get_title_for('add'),
|
|
%{$self->{template_args}}
|
|
);
|
|
}
|
|
|
|
sub action_add_from_order {
|
|
my ($self) = @_;
|
|
# this interfers with init_order
|
|
$self->{converted_from_oe_id} = delete $::form->{id};
|
|
|
|
$self->type_data->validate;
|
|
|
|
my $order = SL::DB::Order->new(id => $self->{converted_from_oe_id})->load;
|
|
|
|
my $target_type = $::form->{type};
|
|
my $delivery_order = SL::Model::Record->new_from_workflow($order, $target_type);
|
|
$self->order($delivery_order);
|
|
|
|
$self->action_add;
|
|
}
|
|
|
|
sub action_add_from_reclamation {
|
|
my ($self) = @_;
|
|
|
|
my $reclamation = SL::DB::Reclamation->new(id => $::form->{from_id})->load;
|
|
my $target_type = $reclamation->is_sales ? 'rma_delivery_order'
|
|
: 'supplier_delivery_order';
|
|
my $delivery_order = SL::Model::Record->new_from_workflow($reclamation, $target_type);
|
|
$self->{converted_from_reclamation_id} = $::form->{from_id};
|
|
$self->order($delivery_order);
|
|
|
|
$self->action_add;
|
|
}
|
|
|
|
# edit an existing order
|
|
sub action_edit {
|
|
my ($self) = @_;
|
|
|
|
if ($::form->{id}) {
|
|
$self->load_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_DELIVERY_ORDER_SAVE())->token;
|
|
}
|
|
}
|
|
|
|
$self->pre_render();
|
|
$self->render(
|
|
'delivery_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::DeliveryOrder->new(id => $multi_ids[0])->load);
|
|
$self->action_save_as_new();
|
|
return;
|
|
}
|
|
|
|
# make new order from given orders
|
|
my @multi_orders = map { SL::DB::DeliveryOrder->new(id => $_)->load } @multi_ids;
|
|
$self->{converted_from_oe_id} = join ' ', map { $_->id } @multi_orders;
|
|
my $target_type = SALES_DELIVERY_ORDER_TYPE();
|
|
my $delivery_order = SL::Model::Record->new_from_workflow_multi(\@multi_orders, $target_type, sort_sources_by => 'transdate');
|
|
$self->order($delivery_order);
|
|
|
|
$self->action_edit();
|
|
}
|
|
|
|
# delete the order
|
|
sub action_delete {
|
|
my ($self) = @_;
|
|
|
|
SL::Model::Record->delete($self->order);
|
|
flash_later('info', $self->type_data->text("delete"));
|
|
|
|
my @redirect_params = (
|
|
action => 'add',
|
|
type => $"DeliveryOrder.pm.html#L1568" data-txt="1568">
$order->taxincluded(defined($order->customer->taxincluded_checked)
|
|
|
? $order->customer->taxincluded_checked
|
|
: $::myconfig{taxincluded_checked});
|
|
}
|
|
|
|
}
|
|
|
|
# setup custom shipto from form
|
|
#
|
|
# The dialog returns form variables starting with 'shipto' and cvars starting
|
|
# with 'shiptocvar_'.
|
|
# Mark it to be deleted if a shipto from master data is selected
|
|
# (i.e. order has a shipto).
|
|
# Else, update or create a new custom shipto. If the fields are empty, it
|
|
# will not be saved on save.
|
|
sub setup_custom_shipto_from_form {
|
|
my ($self, $order, $form) = @_;
|
|
|
|
if ($order->shipto) {
|
|
$self->is_custom_shipto_to_delete(1);
|
|
} else {
|
|
my $custom_shipto = $order->custom_shipto || $order->custom_shipto(SL::DB::Shipto->new(module => 'OE', custom_variables => []));
|
|
|
|
my $shipto_cvars = {map { my ($key) = m{^shiptocvar_(.+)}; $key => delete $form->{$_}} grep { m{^shiptocvar_} } keys %$form};
|
|
my $shipto_attrs = {map { $_ => delete $form->{$_}} grep { m{^shipto} } keys %$form};
|
|
|
|
$custom_shipto->assign_attributes(%$shipto_attrs);
|
|
$custom_shipto->cvar_by_name($_)->value($shipto_cvars->{$_}) for keys %$shipto_cvars;
|
|
}
|
|
}
|
|
|
|
# get data for saving, printing, ..., that is not changed in the form
|
|
#
|
|
# Only cvars for now.
|
|
sub get_unalterable_data {
|
|
my ($self) = @_;
|
|
|
|
foreach my $item (@{ $self->order->items }) {
|
|
# autovivify all cvars that are not in the form (cvars_by_config can do it).
|
|
# workaround to pre-parse number-cvars (parse_custom_variable_values does not parse number values).
|
|
foreach my $var (@{ $item->cvars_by_config }) {
|
|
$var->unparsed_value($::form->parse_amount(\%::myconfig, $var->{__unparsed_value})) if ($var->config->type eq 'number' && exists($var->{__unparsed_value}));
|
|
}
|
|
$item->parse_custom_variable_values;
|
|
}
|
|
}
|
|
|
|
# save the order
|
|
#
|
|
# And delete items that are deleted in the form.
|
|
sub save {
|
|
my ($self) = @_;
|
|
|
|
my $errors = [];
|
|
my $db = $self->order->db;
|
|
|
|
if (scalar @{$self->order->items} == 0 && !grep { $self->type eq $_ } @{$::instance_conf->get_allowed_documents_with_no_positions() || []}) {
|
|
return [t8('The action you\'ve chosen has not been executed because the document does not contain any item yet.')];
|
|
}
|
|
|
|
# link records
|
|
if ($::form->{converted_from_oe_id}) {
|
|
my @converted_from_oe_ids = split ' ', $::form->{converted_from_oe_id};
|
|
set_record_link_conversions(
|
|
$self->order,
|
|
'SL::DB::Order' => \@converted_from_oe_ids,
|
|
'SL::DB::OrderItem' => $::form->{converted_from_orderitems_ids},
|
|
);
|
|
}
|
|
if ($::form->{converted_from_reclamation_id}) {
|
|
my @converted_from_reclamation_ids = split ' ', $::form->{converted_from_reclamation_id};
|
|
set_record_link_conversions(
|
|
$self->order,
|
|
'SL::DB::Reclamation' => \@converted_from_reclamation_ids,
|
|
'SL::DB::ReclamationItem' => $::form->{converted_from_reclamation_items_ids},
|
|
);
|
|
}
|
|
|
|
$db->with_transaction(sub {
|
|
my $validity_token;
|
|
if (!$self->order->id) {
|
|
$validity_token = SL::DB::Manager::ValidityToken->fetch_valid_token(
|
|
scope => SL::DB::ValidityToken::SCOPE_DELIVERY_ORDER_SAVE(),
|
|
token => $::form->{form_validity_token},
|
|
);
|
|
|
|
die $::locale->text('The form is not valid anymore.') if !$validity_token;
|
|
}
|
|
|
|
# delete custom shipto if it is to be deleted or if it is empty
|
|
if ($self->order->custom_shipto && ($self->is_custom_shipto_to_delete || $self->order->custom_shipto->is_empty)) {
|
|
$self->order->custom_shipto->delete if $self->order->custom_shipto->shipto_id;
|
|
$self->order->custom_shipto(undef);
|
|
}
|
|
|
|
SL::DB::DeliveryOrderItem->new(id => $_)->delete for @{$self->item_ids_to_delete || []};
|
|
$self->order->save(cascade => 1);
|
|
|
|
$self->save_history('SAVED');
|
|
|
|
$validity_token->delete if $validity_token;
|
|
delete $::form->{form_validity_token};
|
|
|
|
1;
|
|
}) || push(@{$errors}, $db->error);
|
|
|
|
return $errors;
|
|
}
|
|
|
|
sub workflow_sales_or_request_for_quotation {
|
|
my ($self) = @_;
|
|
|
|
# always save
|
|
my $errors = $self->save();
|
|
|
|
if (scalar @{ $errors }) {
|
|
$self->js->flash('error', $_) for @{ $errors };
|
|
return $self->js->render();
|
|
}
|
|
|
|
my $destination_type = $self->type_data->workflow("to_quotation_type");
|
|
|
|
my $delivery_order = SL::Model::Record->new_from_workflow($self->order, $destination_type, {});
|
|
$self->order($delivery_order);
|
|
$self->{converted_from_oe_id} = delete $::form->{id};
|
|
|
|
# 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);
|
|
}
|
|
|
|
# change form type
|
|
$::form->{type} = $destination_type;
|
|
$self->type($self->init_type);
|
|
$self->cv ($self->init_cv);
|
|
$self->check_auth;
|
|
|
|
$self->get_unalterable_data();
|
|
$self->pre_render();
|
|
|
|
# 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 };
|
|
|
|
$self->render(
|
|
'delivery_order/form',
|
|
title => $self->get_title_for('edit'),
|
|
%{$self->{template_args}}
|
|
);
|
|
}
|
|
|
|
sub workflow_sales_or_purchase_order {
|
|
my ($self) = @_;
|
|
|
|
# always save
|
|
my $errors = $self->save();
|
|
|
|
if (scalar @{ $errors }) {
|
|
$self->js->flash('error', $_) foreach @{ $errors };
|
|
return $self->js->render();
|
|
}
|
|
|
|
my $destination_type = $self->type_data->workflow("to_order_type");
|
|
|
|
# check for direct delivery
|
|
# copy shipto in custom shipto (custom shipto will be copied by new_from() in case)
|
|
my $custom_shipto;
|
|
if ($self->type_data->workflow("to_order_copy_shipto") && $::form->{use_shipto} && $self->order->shipto) {
|
|
$custom_shipto = $self->order->shipto->clone('SL::DB::DeliveryOrder');
|
|
}
|
|
|
|
my $delivery_order = SL::Model::Record->new_from_workflow($self->order, $destination_type, {});
|
|
$self->order($delivery_order);
|
|
$self->{converted_from_oe_id} = delete $::form->{id};
|
|
|
|
# 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);
|
|
}
|
|
|
|
if ($self->type_data->workflow("to_order_copy_shipto")) {
|
|
if ($::form->{use_shipto}) {
|
|
$self->order->custom_shipto($custom_shipto) if $custom_shipto;
|
|
} else {
|
|
# remove any custom shipto if not wanted
|
|
$self->order->custom_shipto(SL::DB::Shipto->new(module => 'OE', custom_variables => []));
|
|
}
|
|
}
|
|
|
|
# change form type
|
|
$::form->{type} = $destination_type;
|
|
$self->type($self->init_type);
|
|
$self->cv ($self->init_cv);
|
|
$self->check_auth;
|
|
|
|
$self->get_unalterable_data();
|
|
$self->pre_render();
|
|
|
|
# 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 };
|
|
|
|
$self->render(
|
|
'delivery_order/form',
|
|
title => $self->get_title_for('edit'),
|
|
%{$self->{template_args}}
|
|
);
|
|
}
|
|
|
|
sub pre_render {
|
|
my ($self) = @_;
|
|
|
|
$self->{all_taxzones} = SL::DB::Manager::TaxZone->get_all_sorted();
|
|
$self->{all_currencies} = SL::DB::Manager::Currency->get_all_sorted();
|
|
$self->{all_departments} = SL::DB::Manager::Department->get_all_sorted();
|
|
$self->{all_languages} = SL::DB::Manager::Language->get_all_sorted( query => [ or => [ obsolete => 0, id => $self->order->language_id ] ] );
|
|
$self->{all_employees} = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->employee_id,
|
|
deleted => 0 ] ],
|
|
sort_by => 'name');
|
|
$self->{all_salesmen} = SL::DB::Manager::Employee->get_all(where => [ or => [ id => $self->order->salesman_id,
|
|
deleted => 0 ] ],
|
|
sort_by => 'name');
|
|
$self->{all_payment_terms} = SL::DB::Manager::PaymentTerm->get_all_sorted(where => [ or => [ id => $self->order->payment_id,
|
|
obsolete => 0 ] ]);
|
|
$self->{all_delivery_terms} = SL::DB::Manager::DeliveryTerm->get_all_sorted();
|
|
$self->{current_employee_id} = SL::DB::Manager::Employee->current->id;
|
|
$self->{order_probabilities} = [ map { { title => ($_ * 10) . '%', id => $_ * 10 } } (0..10) ];
|
|
$self->{positions_scrollbar_height} = SL::Helper::UserPreferences::PositionsScrollbar->new()->get_height();
|
|
|
|
my $print_form = Form->new('');
|
|
$print_form->{type} = $self->type;
|
|
$print_form->{printers} = SL::DB::Manager::Printer->get_all_sorted;
|
|
$self->{print_options} = SL::Helper::PrintOptions->get_print_options(
|
|
form => $print_form,
|
|
options => {dialog_name_prefix => 'print_options.',
|
|
show_headers => 1,
|
|
no_queue => 1,
|
|
no_postscript => 1,
|
|
no_opendocument => 0,
|
|
no_html => 1},
|
|
);
|
|
|
|
foreach my $item (@{$self->order->orderitems}) {
|
|
my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order);
|
|
$item->active_price_source( $price_source->price_from_source( $item->active_price_source ));
|
|
$item->active_discount_source($price_source->discount_from_source($item->active_discount_source));
|
|
}
|
|
|
|
if ($self->order->${\ $self->type_data->properties("nr_key") } && $::instance_conf->get_webdav) {
|
|
my $webdav = SL::Webdav->new(
|
|
type => $self->type,
|
|
number => $self->order->number,
|
|
);
|
|
my @all_objects = $webdav->get_all_objects;
|
|
@{ $self->{template_args}->{WEBDAV} } = map { { name => $_->filename,
|
|
type => t8('File'),
|
|
link => File::Spec->catfile($_->full_filedescriptor),
|
|
} } @all_objects;
|
|
}
|
|
|
|
$self->{template_args}{in_out} = $self->type_data->properties("transfer");
|
|
$self->{template_args}{longdescription_dialog_size_percentage} = SL::Helper::UserPreferences::DisplayPreferences->new()->get_longdescription_dialog_size_percentage();
|
|
|
|
$self->get_item_cvpartnumber($_) for @{$self->order->items_sorted};
|
|
|
|
$::request->{layout}->use_javascript("${_}.js") for qw(kivi.SalesPurchase kivi.DeliveryOrder kivi.File
|
|
calculate_qty kivi.Validator follow_up show_history);
|
|
$self->setup_edit_action_bar;
|
|
}
|
|
|
|
sub setup_edit_action_bar {
|
|
my ($self, %params) = @_;
|
|
|
|
my $deletion_allowed = $self->type_data->show_menu("delete");
|
|
my $may_edit_create = $::auth->assert($self->type_data->rights('edit') || 'DOES_NOT_EXIST', 1);
|
|
|
|
for my $bar ($::request->layout->get('actionbar')) {
|
|
$bar->add(
|
|
combobox => [
|
|
action => [
|
|
t8('Save'),
|
|
id => 'save_action',
|
|
call => [ 'kivi.DeliveryOrder.save', { action => 'save',
|
|
warn_on_duplicates => $::instance_conf->get_order_warn_duplicate_parts,
|
|
warn_on_reqdate => $::instance_conf->get_order_warn_no_deliverydate },
|
|
],
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
|
|
: $self->order->delivered ? t8('This record has already been delivered.')
|
|
: undef,
|
|
],
|
|
action => [
|
|
t8('Save as new'),
|
|
call => [ 'kivi.DeliveryOrder.save', { action => 'save_as_new',
|
|
warn_on_duplicates => $::instance_conf->get_order_warn_duplicate_parts },
|
|
],
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.')
|
|
: $self->type eq 'supplier_delivery_order' ? t8('Need a workflow for Supplier Delivery Order')
|
|
: $self->type eq 'rma_delivery_order' ? t8('Need a workflow for RMA Delivery Order.')
|
|
: !$self->order->id ? t8('This object has not been saved yet.')
|
|
: undef,
|
|
],
|
|
], # end of combobox "Save"
|
|
|
|
combobox => [
|
|
action => [
|
|
t8('Workflow'),
|
|
],
|
|
action => [
|
|
t8('Save and Quotation'),
|
|
submit => [ '#order_form', { action => "DeliveryOrder/sales_quotation" } ],
|
|
only_if => $self->type_data->show_menu("save_and_quotation"),
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
action => [
|
|
t8('Save and RFQ'),
|
|
submit => [ '#order_form', { action => "DeliveryOrder/request_for_quotation" } ],
|
|
only_if => $self->type_data->show_menu("save_and_rfq"),
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
action => [
|
|
t8('Save and Sales Order'),
|
|
submit => [ '#order_form', { action => "DeliveryOrder/sales_order" } ],
|
|
only_if => $self->type_data->show_menu("save_and_sales_order"),
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
action => [
|
|
t8('Save and Purchase Order'),
|
|
call => [ 'kivi.DeliveryOrder.purchase_order_check_for_direct_delivery' ],
|
|
only_if => $self->type_data->show_menu("save_and_purchase_order"),
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
action => [
|
|
t8('Save and Delivery Order'),
|
|
call => [ 'kivi.DeliveryOrder.save', { action => 'save_and_delivery_order',
|
|
warn_on_duplicates => $::instance_conf->get_order_warn_duplicate_parts,
|
|
warn_on_reqdate => $::instance_conf->get_order_warn_no_deliverydate },
|
|
],
|
|
only_if => $self->type_data->show_menu("save_and_delivery_order"),
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
action => [
|
|
t8('Save and Invoice'),
|
|
call => [ 'kivi.DeliveryOrder.save', { action => 'save_and_invoice',
|
|
warn_on_duplicates => $::instance_conf->get_order_warn_duplicate_parts },
|
|
],
|
|
only_if => $self->type_data->show_menu("save_and_invoice"),
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
action => [
|
|
t8('Save and AP Transaction'),
|
|
call => [ 'kivi.DeliveryOrder.save', { action => 'save_and_ap_transaction',
|
|
warn_on_duplicates => $::instance_conf->get_order_warn_duplicate_parts },
|
|
],
|
|
only_if => $self->type_data->show_menu("save_and_ap_transaction"),
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
|
|
], # end of combobox "Workflow"
|
|
|
|
combobox => [
|
|
action => [
|
|
t8('Export'),
|
|
],
|
|
action => [
|
|
t8('Save and preview PDF'),
|
|
call => [ 'kivi.DeliveryOrder.save', { action => 'preview_pdf',
|
|
warn_on_duplicates => $::instance_conf->get_order_warn_duplicate_parts,
|
|
warn_on_reqdate => $::instance_conf->get_order_warn_no_deliverydate },
|
|
],
|
|
disabled => !$may_edit_create ? t8('You do not have the permissions to access this function.') : undef,
|
|
],
|
|
action => [
|
|
t8('Save and print'),
|
|
call => [ 'kivi.DeliveryOrder.show_print_options', { warn_on_duplicates => $::instance_conf->get_order_warn_duplicate_parts,
|
|