use SL::DB::PartClassification;
use SL::DB::PartsGroup;
use SL::DB::Printer;
+use SL::DB::Note;
use SL::DB::Language;
use SL::DB::RecordLink;
use SL::DB::RequirementSpec;
$self->js_reset_order_and_item_ids_after_save;
+ my $redirect_url = $self->url_for(
+ action => 'edit',
+ type => $self->type,
+ id => $self->order->id,
+ );
+
my $format = $::form->{print_options}->{format};
my $media = $::form->{print_options}->{media};
my $formname = $::form->{print_options}->{formname};
# only PDF, OpenDocument & HTML for now
if (none { $format eq $_ } qw(pdf opendocument opendocument_pdf html)) {
- return $self->js->flash('error', t8('Format \'#1\' is not supported yet/anymore.', $format))->render;
+ flash_later('error', t8('Format \'#1\' is not supported yet/anymore.', $format));
+ return $self->js->redirect_to($redirect_url)->render;
}
# only screen or printer by now
if (none { $media eq $_ } qw(screen printer)) {
- return $self->js->flash('error', t8('Media \'#1\' is not supported yet/anymore.', $media))->render;
+ flash_later('error', t8('Media \'#1\' is not supported yet/anymore.', $media));
+ return $self->js->redirect_to($redirect_url)->render;
}
# create a form for generate_attachment_filename
printer_id => $printer_id,
groupitems => $groupitems });
if (scalar @errors) {
- return $self->js->flash('error', t8('Generating the document failed: #1', $errors[0]))->render;
+ flash_later('error', t8('Generating the document failed: #1', $errors[0]));
+ return $self->js->redirect_to($redirect_url)->render;
}
if ($media eq 'screen') {
# screen/download
- $self->js->flash('info', t8('The document has been created.'));
+ flash_later('info', t8('The document has been created.'));
$self->send_file(
\$doc,
type => SL::MIME->mime_type_from_ext($doc_filename),
content => $doc,
);
- $self->js->flash('info', t8('The document has been printed.'));
+ flash_later('info', t8('The document has been printed.'));
}
my @warnings = $self->store_doc_to_webdav_and_filemanagement($doc, $doc_filename, $formname);
if (scalar @warnings) {
- $self->js->flash('warning', $_) for @warnings;
+ flash_later('warning', $_) for @warnings;
}
$self->save_history('PRINTED');
- $self->js
- ->run('kivi.ActionBar.setEnabled', '#save_and_email_action')
- ->render;
+ $self->js->redirect_to($redirect_url)->render;
}
+
sub action_preview_pdf {
my ($self) = @_;
$self->js_reset_order_and_item_ids_after_save;
+ my $redirect_url = $self->url_for(
+ action => 'edit',
+ type => $self->type,
+ id => $self->order->id,
+ );
+
my $format = 'pdf';
my $media = 'screen';
my $formname = $self->type;
language => $self->order->language,
});
if (scalar @errors) {
- return $self->js->flash('error', t8('Conversion to PDF failed: #1', $errors[0]))->render;
+ flash_later('error', t8('Conversion to PDF failed: #1', $errors[0]));
+ return $self->js->redirect_to($redirect_url)->render;
}
+
$self->save_history('PREVIEWED');
- $self->js->flash('info', t8('The PDF has been previewed'));
+
+ flash_later('info', t8('The PDF has been previewed'));
+
# screen/download
$self->send_file(
\$pdf,
type => SL::MIME->mime_type_from_ext($pdf_filename),
name => $pdf_filename,
- js_no_render => 0,
+ js_no_render => 1,
);
+
+ $self->js->redirect_to($redirect_url)->render;
}
# open the email dialog
return $self->js->render();
}
+ $self->js_reset_order_and_item_ids_after_save;
+
my $cv_method = $self->cv;
if (!$self->order->$cv_method) {
my $record = $self->order;
my $item = SL::DB::OrderItem->new(%$form_attr);
- my $part = SL::DB::Part->new(id => $::form->{add_item}->{parts_id})->load;
- my $price_source = SL::PriceSource->new(record_item => $item, record => $record);
-
- $item->unit($part->unit);
+ $item->unit($item->part->unit);
- my $price_src;
- if ( $part->is_assortment ) {
- # add assortment items with price 0, as the components carry the price
- $price_src = $price_source->price_from_source("");
- $price_src->price(0);
- } elsif (defined $item->sellprice) {
- $price_src = $price_source->price_from_source("");
- $price_src->price($item->sellprice);
- } else {
- $price_src = $price_source->best_price
- ? $price_source->best_price
- : $price_source->price_from_source("");
- $price_src->price($::form->round_amount($price_src->price / $record->exchangerate, 5)) if $record->exchangerate;
- $price_src->price(0) if !$price_source->best_price;
- }
-
- my $discount_src;
- if (defined $item->discount) {
- $discount_src = $price_source->discount_from_source("");
- $discount_src->discount($item->discount);
- } else {
- $discount_src = $price_source->best_discount
- ? $price_source->best_discount
- : $price_source->discount_from_source("");
- $discount_src->discount(0) if !$price_source->best_discount;
- }
+ my ($price_src, $discount_src) = get_best_price_and_discount_source($record, $item, 0);
$self->js
->val ('#add_item_unit', $item->unit)
- ->val ('#add_item_description', $part->description)
+ ->val ('#add_item_description', $item->part->description)
->val ('#add_item_sellprice_as_number', '')
->attr ('#add_item_sellprice_as_number', 'placeholder', $price_src->price_as_number)
->attr ('#add_item_sellprice_as_number', 'title', $price_src->source_description)
$item->description($texts->{description});
$item->longdescription($texts->{longdescription});
- my $price_source = SL::PriceSource->new(record_item => $item, record => $self->order);
-
- my $price_src;
- if ($item->part->is_assortment) {
- # add assortment items with price 0, as the components carry the price
- $price_src = $price_source->price_from_source("");
- $price_src->price(0);
- } else {
- $price_src = $price_source->best_price
- ? $price_source->best_price
- : $price_source->price_from_source("");
- $price_src->price($::form->round_amount($price_src->price / $self->order->exchangerate, 5)) if $self->order->exchangerate;
- $price_src->price(0) if !$price_source->best_price;
- }
-
- my $discount_src;
- $discount_src = $price_source->best_discount
- ? $price_source->best_discount
- : $price_source->discount_from_source("");
- $discount_src->discount(0) if !$price_source->best_discount;
+ my ($price_src, $discount_src) = get_best_price_and_discount_source($self->order, $item, 1);
$item->sellprice($price_src->price);
$item->active_price_source($price_src);
$self->js->render();
}
+sub action_save_phone_note {
+ my ($self) = @_;
+
+ if (!$::form->{phone_note}->{subject} || !$::form->{phone_note}->{body}) {
+ return $self->js->flash('error', t8('Phone note needs a subject and a body.'))->render;
+ }
+
+ my $phone_note;
+ if ($::form->{phone_note}->{id}) {
+ $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+ return $self->js->flash('error', t8('Phone note not found for this order.'))->render if !$phone_note;
+ }
+
+ $phone_note = SL::DB::Note->new() if !$phone_note;
+ my $is_new = !$phone_note->id;
+
+ $phone_note->assign_attributes(%{ $::form->{phone_note} },
+ trans_id => $self->order->id,
+ trans_module => 'oe',
+ employee => SL::DB::Manager::Employee->current);
+
+ $phone_note->save;
+ $self->order(SL::DB::Order->new(id => $self->order->id)->load);
+
+ my $tab_as_html = $self->p->render('order/tabs/phone_notes', SELF => $self);
+
+ return $self->js
+ ->replaceWith('#phone-notes', $tab_as_html)
+ ->html('#num_phone_notes', (scalar @{$self->order->phone_notes}) ? ' (' . scalar @{$self->order->phone_notes} . ')' : '')
+ ->flash('info', $is_new ? t8('Phone note has been created.') : t8('Phone note has been updated.'))
+ ->render;
+}
+
+sub action_delete_phone_note {
+ my ($self) = @_;
+
+ my $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+
+ return $self->js->flash('error', t8('Phone note not found for this order.'))->render if !$phone_note;
+
+ $phone_note->delete;
+ $self->order(SL::DB::Order->new(id => $self->order->id)->load);
+
+ my $tab_as_html = $self->p->render('order/tabs/phone_notes', SELF => $self);
+
+ return $self->js
+ ->replaceWith('#phone-notes', $tab_as_html)
+ ->html('#num_phone_notes', (scalar @{$self->order->phone_notes}) ? ' (' . scalar @{$self->order->phone_notes} . ')' : '')
+ ->flash('info', t8('Phone note has been deleted.'))
+ ->render;
+}
+
sub js_load_second_row {
my ($self, $item, $item_id, $do_parse) = @_;
}
$item->assign_attributes(%$attr);
+ $item->qty(1.0) if !$item->qty;
+ $item->unit($item->part->unit) if !$item->unit;
- my $part = SL::DB::Part->new(id => $attr->{parts_id})->load;
- my $price_source = SL::PriceSource->new(record_item => $item, record => $record);
-
- $item->qty(1.0) if !$item->qty;
- $item->unit($part->unit) if !$item->unit;
-
- my $price_src;
- if ( $part->is_assortment ) {
- # add assortment items with price 0, as the components carry the price
- $price_src = $price_source->price_from_source("");
- $price_src->price(0);
- } elsif (defined $item->sellprice) {
- $price_src = $price_source->price_from_source("");
- $price_src->price($item->sellprice);
- } else {
- $price_src = $price_source->best_price
- ? $price_source->best_price
- : $price_source->price_from_source("");
- $price_src->price($::form->round_amount($price_src->price / $record->exchangerate, 5)) if $record->exchangerate;
- $price_src->price(0) if !$price_source->best_price;
- }
-
- my $discount_src;
- if (defined $item->discount) {
- $discount_src = $price_source->discount_from_source("");
- $discount_src->discount($item->discount);
- } else {
- $discount_src = $price_source->best_discount
- ? $price_source->best_discount
- : $price_source->discount_from_source("");
- $discount_src->discount(0) if !$price_source->best_discount;
- }
+ my ($price_src, $discount_src) = get_best_price_and_discount_source($record, $item, 0);
my %new_attr;
- $new_attr{part} = $part;
- $new_attr{description} = $part->description if ! $item->description;
- $new_attr{price_factor_id} = $part->price_factor_id if ! $item->price_factor_id;
+ $new_attr{description} = $item->part->description if ! $item->description;
+ $new_attr{qty} = 1.0 if ! $item->qty;
+ $new_attr{price_factor_id} = $item->part->price_factor_id if ! $item->price_factor_id;
$new_attr{sellprice} = $price_src->price;
$new_attr{discount} = $discount_src->discount;
$new_attr{active_price_source} = $price_src;
$new_attr{active_discount_source} = $discount_src;
- $new_attr{longdescription} = $part->notes if ! defined $attr->{longdescription};
+ $new_attr{longdescription} = $item->part->notes if ! defined $attr->{longdescription};
$new_attr{project_id} = $record->globalproject_id;
- $new_attr{lastcost} = $record->is_sales ? $part->lastcost : 0;
+ $new_attr{lastcost} = $record->is_sales ? $item->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
# saved. Adding empty custom_variables to new orderitem here solves this problem.
$new_attr{custom_variables} = [];
- my $texts = get_part_texts($part, $record->language_id, description => $new_attr{description}, longdescription => $new_attr{longdescription});
+ my $texts = get_part_texts($item->part, $record->language_id, description => $new_attr{description}, longdescription => $new_attr{longdescription});
$item->assign_attributes(%new_attr, %{ $texts });
my $errors = [];
my $db = $self->order->db;
+ # check for new or updated phone note
+ if ($::form->{phone_note}->{subject} || $::form->{phone_note}->{body}) {
+ if (!$::form->{phone_note}->{subject} || !$::form->{phone_note}->{body}) {
+ return [t8('Phone note needs a subject and a body.')];
+ }
+
+ my $phone_note;
+ if ($::form->{phone_note}->{id}) {
+ $phone_note = first { $_->id == $::form->{phone_note}->{id} } @{$self->order->phone_notes};
+ return [t8('Phone note not found for this order.')] if !$phone_note;
+ }
+
+ $phone_note = SL::DB::Note->new() if !$phone_note;
+ my $is_new = !$phone_note->id;
+
+ $phone_note->assign_attributes(%{ $::form->{phone_note} },
+ trans_id => $self->order->id,
+ trans_module => 'oe',
+ employee => SL::DB::Manager::Employee->current);
+
+ $self->order->add_phone_notes($phone_note) if $is_new;
+ }
+
$db->with_transaction(sub {
# 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->get_item_cvpartnumber($_) for @{$self->order->items_sorted};
+ $self->{template_args}->{num_phone_notes} = scalar @{ $self->order->phone_notes || [] };
+
$::request->{layout}->use_javascript("${_}.js") for qw(kivi.Validator kivi.SalesPurchase kivi.Order kivi.File ckeditor/ckeditor ckeditor/adapters/jquery
edit_periodic_invoices_config calculate_qty follow_up show_history);
$self->setup_edit_action_bar;
return $texts;
}
+sub get_best_price_and_discount_source {
+ my ($record, $item, $ignore_given) = @_;
+
+ my $price_source = SL::PriceSource->new(record_item => $item, record => $record);
+
+ my $price_src;
+ if ( $item->part->is_assortment ) {
+ # add assortment items with price 0, as the components carry the price
+ $price_src = $price_source->price_from_source("");
+ $price_src->price(0);
+ } elsif (!$ignore_given && defined $item->sellprice) {
+ $price_src = $price_source->price_from_source("");
+ $price_src->price($item->sellprice);
+ } else {
+ $price_src = $price_source->best_price
+ ? $price_source->best_price
+ : $price_source->price_from_source("");
+ $price_src->price($::form->round_amount($price_src->price / $record->exchangerate, 5)) if $record->exchangerate;
+ $price_src->price(0) if !$price_source->best_price;
+ }
+
+ my $discount_src;
+ if (!$ignore_given && defined $item->discount) {
+ $discount_src = $price_source->discount_from_source("");
+ $discount_src->discount($item->discount);
+ } else {
+ $discount_src = $price_source->best_discount
+ ? $price_source->best_discount
+ : $price_source->discount_from_source("");
+ $discount_src->discount(0) if !$price_source->best_discount;
+ }
+
+ return ($price_src, $discount_src);
+}
+
sub sales_order_type {
'sales_order';
}