use SL::PriceSource;
use SL::Webdav;
use SL::File;
-
+use SL::Util qw(trim);
use SL::DB::Order;
use SL::DB::Default;
use SL::DB::Unit;
use SL::DB::Part;
use SL::DB::Printer;
use SL::DB::Language;
+use SL::DB::RecordLink;
use SL::Helper::CreatePDF qw(:all);
use SL::Helper::PrintOptions;
__PACKAGE__->run_before('_check_auth');
__PACKAGE__->run_before('_recalc',
- only => [ qw(save save_and_delivery_order save_and_invoice print create_pdf send_email) ]);
+ only => [ qw(save save_as_new save_and_delivery_order save_and_invoice print create_pdf send_email) ]);
__PACKAGE__->run_before('_get_unalterable_data',
- only => [ qw(save save_and_delivery_order save_and_invoice print create_pdf send_email) ]);
+ only => [ qw(save save_as_new save_and_delivery_order save_and_invoice print create_pdf send_email) ]);
#
# actions
$self->_pre_render();
$self->render(
'order/form',
- title => $self->type eq _sales_order_type() ? $::locale->text('Add Sales Order')
- : $self->type eq _purchase_order_type() ? $::locale->text('Add Purchase Order')
- : '',
+ title => $self->_get_title_for('add'),
%{$self->{template_args}}
);
}
$self->_pre_render();
$self->render(
'order/form',
- title => $self->type eq _sales_order_type() ? $::locale->text('Edit Sales Order')
- : $self->type eq _purchase_order_type() ? $::locale->text('Edit Purchase Order')
- : '',
+ title => $self->_get_title_for('edit'),
%{$self->{template_args}}
);
}
return $self->js->render();
}
- flash_later('info', $::locale->text('The order has been deleted'));
+ my $text = $self->type eq _sales_order_type() ? $::locale->text('The order 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')
+ : '';
+ flash_later('info', $text);
+
my @redirect_params = (
action => 'add',
type => $self->type,
return $self->js->render();
}
- flash_later('info', $::locale->text('The order has been saved'));
+ my $text = $self->type eq _sales_order_type() ? $::locale->text('The order 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')
+ : '';
+ flash_later('info', $text);
+
my @redirect_params = (
action => 'edit',
type => $self->type,
$self->redirect_to(@redirect_params);
}
+# save the order as new document an open it for edit
+sub action_save_as_new {
+ my ($self) = @_;
+
+ if (!$self->order->id) {
+ $self->js->flash('error', t8('This object has not been saved yet.'));
+ return $self->js->render();
+ }
+
+ delete $::form->{$_} for qw(closed delivered converted_from_oe_id converted_from_orderitems_ids);
+
+ my $src_order = SL::DB::Order->new(id => $self->order->id)->load;
+
+ # Lets assign a new number if the user hasn't changed the previous one.
+ # If it has been changed manually then use it as-is.
+ if (trim($self->order->number) eq $src_order->number) {
+ $self->order->number('');
+ }
+
+ # Clear reqdate and transdate unless changed
+ if ($self->order->transdate == $src_order->transdate) {
+ $self->order->transdate(DateTime->today_local)
+ }
+ if ($self->order->reqdate == $src_order->reqdate) {
+ my $extra_days = $self->type eq _sales_quotation_type() ? $::instance_conf->get_reqdate_interval : 1;
+ $self->order->reqdate(DateTime->today_local->next_workday(extra_days => $extra_days));
+ }
+
+ # Update employee
+ $self->order->employee(SL::DB::Manager::Employee->current);
+
+ # save
+ $self->action_save();
+}
+
# print the order
#
# This is called if "print" is pressed in the print dialog.
$self->js->flash('error', $_) foreach @{ $errors };
return $self->js->render();
}
- flash_later('info', $::locale->text('The order has been saved'));
+
+ my $text = $self->type eq _sales_order_type() ? $::locale->text('The order 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')
+ : '';
+ flash_later('info', $text);
my @redirect_params = (
controller => 'oe.pl',
$self->js->flash('error', $_) foreach @{ $errors };
return $self->js->render();
}
- flash_later('info', $::locale->text('The order has been saved'));
+
+ my $text = $self->type eq _sales_order_type() ? $::locale->text('The order 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')
+ : '';
+ flash_later('info', $text);
my @redirect_params = (
controller => 'oe.pl',
$self->redirect_to(@redirect_params);
}
+# workflow from sales quotation to sales order
+sub action_sales_order {
+ $_[0]->_workflow_sales_or_purchase_order();
+}
+
+# workflow from rfq to purchase order
+sub action_purchase_order {
+ $_[0]->_workflow_sales_or_purchase_order();
+}
+
# set form elements in respect to a changed customer or vendor
#
# This action is called on an change of the customer/vendor picker.
#
sub init_valid_types {
- [ _sales_order_type(), _purchase_order_type() ];
+ [ _sales_order_type(), _purchase_order_type(), _sales_quotation_type(), _request_quotation_type() ];
}
sub init_type {
sub init_cv {
my ($self) = @_;
- my $cv = $self->type eq _sales_order_type() ? 'customer'
- : $self->type eq _purchase_order_type() ? 'vendor'
+ my $cv = (any { $self->type eq $_ } (_sales_order_type(), _sales_quotation_type())) ? 'customer'
+ : (any { $self->type eq $_ } (_purchase_order_type(), _request_quotation_type())) ? 'vendor'
: die "Not a valid type for order";
return $cv;
# order here solves this problem.
my $order;
$order = SL::DB::Manager::Order->find_by(id => $::form->{id}) if $::form->{id};
- $order ||= SL::DB::Order->new(orderitems => []);
+ $order ||= SL::DB::Order->new(orderitems => [],
+ quotation => (any { $self->type eq $_ } (_sales_quotation_type(), _request_quotation_type())));
my $form_orderitems = delete $::form->{order}->{orderitems};
my $form_periodic_invoices_config = delete $::form->{order}->{periodic_invoices_config};
$item ||= SL::DB::OrderItem->new(custom_variables => []);
$item->assign_attributes(%$attr);
- $item->longdescription($item->part->notes) if $is_new && !defined $attr->{longdescription};
- $item->project_id($record->globalproject_id) if $is_new && !defined $attr->{project_id};
- $item->lastcost($item->part->lastcost) if $is_new && !defined $attr->{lastcost_as_number};
+ $item->longdescription($item->part->notes) if $is_new && !defined $attr->{longdescription};
+ $item->project_id($record->globalproject_id) if $is_new && !defined $attr->{project_id};
+ $item->lastcost($record->is_sales ? $item->part->lastcost : 0) if $is_new && !defined $attr->{lastcost_as_number};
return $item;
}
$new_attr{active_discount_source} = $discount_src;
$new_attr{longdescription} = $part->notes if ! defined $attr->{longdescription};
$new_attr{project_id} = $record->globalproject_id;
- $new_attr{lastcost} = $part->lastcost;
+ $new_attr{lastcost} = $record->is_sales ? $part->lastcost : 0;
# add_custom_variables adds cvars to an orderitem with no cvars for saving, but
# they cannot be retrieved via custom_variables until the order/orderitem is
$db->with_transaction(sub {
SL::DB::OrderItem->new(id => $_)->delete for @{$self->item_ids_to_delete};
$self->order->save(cascade => 1);
+
+ # link records
+ if ($::form->{converted_from_oe_id}) {
+ SL::DB::Order->new(id => $::form->{converted_from_oe_id})->load->link_to_record($self->order);
+
+ if (scalar @{ $::form->{converted_from_orderitems_ids} || [] }) {
+ my $idx = 0;
+ foreach (@{ $self->order->items_sorted }) {
+ my $from_id = $::form->{converted_from_orderitems_ids}->[$idx];
+ next if !$from_id;
+ SL::DB::RecordLink->new(from_table => 'orderitems',
+ from_id => $from_id,
+ to_table => 'orderitems',
+ to_id => $_->id
+ )->save;
+ $idx++;
+ }
+ }
+ }
+ 1;
}) || push(@{$errors}, $db->error);
return $errors;
}
+sub _workflow_sales_or_purchase_order {
+ my ($self) = @_;
+
+ my $destination_type = $::form->{type} eq _sales_quotation_type() ? _sales_order_type()
+ : $::form->{type} eq _request_quotation_type() ? _purchase_order_type()
+ : '';
+
+ $self->order(SL::DB::Order->new_from($self->order, destination_type => $destination_type));
+ $self->{converted_from_oe_id} = delete $::form->{id};
+
+ # change form type
+ $::form->{type} = $destination_type;
+ $self->init_type;
+ $self->_check_auth;
+
+ $self->_recalc();
+ $self->_get_unalterable_data();
+ $self->_pre_render();
+
+ # trigger rendering values for second row/longdescription 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 };
+ $_->{render_longdescription} = 1 for @{ $self->order->items_sorted };
+
+ $self->render(
+ 'order/form',
+ title => $self->_get_title_for('edit'),
+ %{$self->{template_args}}
+ );
+}
+
sub _pre_render {
my ($self) = @_;
$self->{all_delivery_terms} = SL::DB::Manager::DeliveryTerm->get_all_sorted();
$self->{current_employee_id} = SL::DB::Manager::Employee->current->id;
$self->{periodic_invoices_status} = $self->_get_periodic_invoices_status($self->order->periodic_invoices_config);
+ $self->{order_probabilities} = [ map { { title => ($_ * 10) . '%', id => $_ * 10 } } (0..10) ];
my $print_form = Form->new('');
$print_form->{type} = $self->type;
sub _setup_edit_action_bar {
my ($self, %params) = @_;
- my $deletion_allowed = (($self->cv eq 'customer') && $::instance_conf->get_sales_order_show_delete)
- || (($self->cv eq 'vendor') && $::instance_conf->get_purchase_order_show_delete);
+ my $deletion_allowed = (any { $self->type eq $_ } (_sales_quotation_type(), _request_quotation_type()))
+ || (($self->type eq _sales_order_type()) && $::instance_conf->get_sales_order_show_delete)
+ || (($self->type eq _purchase_order_type()) && $::instance_conf->get_purchase_order_show_delete);
for my $bar ($::request->layout->get('actionbar')) {
$bar->add(
combobox => [
action => [
t8('Save'),
- call => [ 'kivi.Order.save', $::instance_conf->get_order_warn_duplicate_parts ],
+ call => [ 'kivi.Order.save', 'save', $::instance_conf->get_order_warn_duplicate_parts ],
+ checks => [ 'kivi.Order.check_save_active_periodic_invoices' ],
+ ],
+ action => [
+ t8('Save as new'),
+ call => [ 'kivi.Order.save', 'save_as_new', $::instance_conf->get_order_warn_duplicate_parts ],
checks => [ 'kivi.Order.check_save_active_periodic_invoices' ],
- accesskey => 'enter',
+ disabled => !$self->order->id ? t8('This object has not been saved yet.') : undef,
],
action => [
t8('Save and Delivery Order'),
- call => [ 'kivi.Order.save_and_delivery_order', $::instance_conf->get_order_warn_duplicate_parts ],
+ call => [ 'kivi.Order.save', 'save_and_delivery_order', $::instance_conf->get_order_warn_duplicate_parts ],
checks => [ 'kivi.Order.check_save_active_periodic_invoices' ],
+ only_if => (any { $self->type eq $_ } (_sales_order_type(), _purchase_order_type()))
],
action => [
t8('Save and Invoice'),
- call => [ 'kivi.Order.save_and_invoice', $::instance_conf->get_order_warn_duplicate_parts ],
+ call => [ 'kivi.Order.save', 'save_and_invoice', $::instance_conf->get_order_warn_duplicate_parts ],
checks => [ 'kivi.Order.check_save_active_periodic_invoices' ],
],
-
], # end of combobox "Save"
+ combobox => [
+ action => [
+ t8('Workflow'),
+ ],
+ action => [
+ t8('Sales Order'),
+ submit => [ '#order_form', { action => "Order/sales_order" } ],
+ only_if => (any { $self->type eq $_ } (_sales_quotation_type())),
+ ],
+ action => [
+ t8('Purchase Order'),
+ submit => [ '#order_form', { action => "Order/purchase_order" } ],
+ only_if => (any { $self->type eq $_ } (_request_quotation_type())),
+ ],
+ ], # end of combobox "Workflow"
+
combobox => [
action => [
t8('Export'),
return $active ? t8('active') : t8('inactive');
}
+sub _get_title_for {
+ my ($self, $action) = @_;
+
+ return '' if none { lc($action)} qw(add edit);
+
+ # for locales:
+ # $::locale->text("Add Sales Order");
+ # $::locale->text("Add Purchase Order");
+ # $::locale->text("Add Quotation");
+ # $::locale->text("Add Request for Quotation");
+ # $::locale->text("Edit Sales Order");
+ # $::locale->text("Edit Purchase Order");
+ # $::locale->text("Edit Quotation");
+ # $::locale->text("Edit Request for Quotation");
+
+ $action = ucfirst(lc($action));
+ return $self->type eq _sales_order_type() ? $::locale->text("$action Sales Order")
+ : $self->type eq _purchase_order_type() ? $::locale->text("$action Purchase Order")
+ : $self->type eq _sales_quotation_type() ? $::locale->text("$action Quotation")
+ : $self->type eq _request_quotation_type() ? $::locale->text("$action Request for Quotation")
+ : '';
+}
+
sub _sales_order_type {
'sales_order';
}
'purchase_order';
}
+sub _sales_quotation_type {
+ 'sales_quotation';
+}
+
+sub _request_quotation_type {
+ 'request_quotation';
+}
+
1;
__END__