use SL::OE;
use Data::Dumper;
use DateTime;
+use List::MoreUtils qw(uniq);
use List::Util qw(max sum);
+use English qw(-no_match_vars);
use SL::DB::Default;
use SL::DB::Customer;
$form->{rowcount} = $i;
}
-
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # Problem: set_pricegroup resets the sellprice of old invoices to the price
- # currently defined in the pricegroup, which is a problem if the price has
- # changed, as the old invoice gets the new price
- # set_pricegroup must never be called, when an old invoice is initially loaded
-
- # set_pricegroup($_) for 1 .. $form->{rowcount};
}
$main::lxdebug->leave_sub();
}
$form->{defaultcurrency} = $form->get_default_currency(\%myconfig);
- my @old_project_ids = ($form->{"globalproject_id"});
- map { push @old_project_ids, $form->{"project_id_$_"} if $form->{"project_id_$_"}; } 1..$form->{"rowcount"};
-
- $form->get_lists("projects" => { "key" => "ALL_PROJECTS",
- "all" => 0,
- "old_id" => \@old_project_ids },
- "taxzones" => "ALL_TAXZONES",
+ $form->get_lists("taxzones" => ($form->{id} ? "ALL_TAXZONES" : "ALL_ACTIVE_TAXZONES"),
"currencies" => "ALL_CURRENCIES",
"customers" => "ALL_CUSTOMERS",
"departments" => "all_departments",
"price_factors" => "ALL_PRICE_FACTORS");
- $TMPL_VAR{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all(query => [ or => [ id => $::form->{employee_id}, deleted => 0 ] ]);
- $TMPL_VAR{ALL_SALESMEN} = SL::DB::Manager::Employee->get_all(query => [ or => [ id => $::form->{salesman_id}, deleted => 0 ] ]);
- $TMPL_VAR{ALL_SHIPTO} = SL::DB::Manager::Shipto->get_all(query => [
+ # Projects
+ my @old_project_ids = uniq grep { $_ } map { $_ * 1 } ($form->{"globalproject_id"}, map { $form->{"project_id_$_"} } 1..$form->{"rowcount"});
+ my @old_ids_cond = @old_project_ids ? (id => \@old_project_ids) : ();
+ my @customer_cond;
+ if ($::instance_conf->get_customer_projects_only_in_sales) {
+ @customer_cond = (
+ or => [
+ customer_id => $::form->{customer_id},
+ billable_customer_id => $::form->{customer_id},
+ ]);
+ }
+ my @conditions = (
+ or => [
+ and => [ active => 1, @customer_cond ],
+ @old_ids_cond,
+ ]);
+
+ $TMPL_VAR{ALL_PROJECTS} = SL::DB::Manager::Project->get_all_sorted(query => \@conditions);
+ $TMPL_VAR{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all_sorted(query => [ or => [ id => $::form->{employee_id}, deleted => 0 ] ]);
+ $TMPL_VAR{ALL_SALESMEN} = SL::DB::Manager::Employee->get_all_sorted(query => [ or => [ id => $::form->{salesman_id}, deleted => 0 ] ]);
+ $TMPL_VAR{ALL_SHIPTO} = SL::DB::Manager::Shipto->get_all_sorted(query => [
or => [ trans_id => $::form->{"$::form->{vc}_id"} * 1, and => [ shipto_id => $::form->{shipto_id} * 1, trans_id => undef ] ]
]);
- $TMPL_VAR{ALL_CONTACTS} = SL::DB::Manager::Contact->get_all(query => [
+ $TMPL_VAR{ALL_CONTACTS} = SL::DB::Manager::Contact->get_all_sorted(query => [
or => [
cp_cv_id => $::form->{"$::form->{vc}_id"} * 1,
and => [
max_dunning_level dunning_amount
shiptoname shiptostreet shiptozipcode shiptocity shiptocountry shiptocontact shiptophone shiptofax
shiptoemail shiptodepartment_1 shiptodepartment_2 shiptocp_gender message email subject cc bcc taxaccounts cursor_fokus
- convert_from_do_ids convert_from_oe_ids
+ convert_from_do_ids convert_from_oe_ids convert_from_ar_ids useasnew
+ invoice_id
show_details
), @custom_hiddens,
map { $_.'_rate', $_.'_description', $_.'_taxnumber' } split / /, $form->{taxaccounts}];
+ $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.SalesPurchase ckeditor/ckeditor ckeditor/adapters/jquery kivi.io autocomplete_customer autocomplete_part));
+
$form->header();
print $form->parse_html_template("is/form_header", \%TMPL_VAR);
my $rows = scalar @{ $form->{item_list} };
- # Falls kein Kundenrabatt vorhanden ist, den aktuellen Rabatt nicht mit 0% überschreiben,
- # da hier der Anwender schon manual einen Wert eingetragen haben könnte (analog zu qty) Bugfix: 1412
- if ($form->{customer_discount}){
- $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{customer_discount} * 100);
- }
+ $form->{"discount_$i"} = $form->parse_amount(\%myconfig, $form->{"discount_$i"}) / 100.0;
+ $form->{"discount_$i"} ||= $form->{customer_discount};
if ($rows) {
$form->{"qty_$i"} = $form->parse_amount(\%myconfig, $form->{"qty_$i"});
if ($rows > 1) {
- select_item(mode => 'IS');
+ select_item(mode => 'IS', pre_entered_qty => $form->{"qty_$i"});
::end_of_request();
} else {
if ($sellprice) {
$form->{"sellprice_$i"} = $sellprice;
} else {
+ my $record = _make_record();
+ my $price_source = SL::PriceSource->new(record_item => $record->items->[$i-1], record => $record);
+ my $best_price = $price_source->best_price;
+ my $best_discount = $price_source->best_discount;
+
+ if ($best_price) {
+ $::form->{"sellprice_$i"} = $best_price->price;
+ $::form->{"active_price_source_$i"} = $best_price->source;
+ }
+ if ($best_discount) {
+ $::form->{"discount_$i"} = $best_discount->discount;
+ $::form->{"active_discount_source_$i"} = $best_discount->source;
+ }
+
# if there is an exchange rate adjust sellprice
- $form->{"sellprice_$i"} *= (1 - $form->{tradediscount});
$form->{"sellprice_$i"} /= $exchangerate;
}
$form->{"listprice_$i"} /= $exchangerate;
- my $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * (1 - $form->{"discount_$i"} / 100);
+ my $amount = $form->{"sellprice_$i"} * $form->{"qty_$i"} * (1 - $form->{"discount_$i"});
map { $form->{"${_}_base"} = 0 } split / /, $form->{taxaccounts};
map { $form->{"${_}_base"} += $amount } split / /, $form->{"taxaccounts_$i"};
map { $amount += ($form->{"${_}_base"} * $form->{"${_}_rate"}) } split / /, $form->{"taxaccounts_$i"} if !$form->{taxincluded};
map { $form->{"${_}_$i"} = $form->format_amount(\%myconfig, $form->{"${_}_$i"}, $decimalplaces) } qw(sellprice lastcost);
- $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
-
- # get pricegroups for parts
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
-
- # build up html code for prices_$i
- &set_pricegroup($i);
+ $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"});
+ $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"discount_$i"} * 100.0);
}
&display_form;
}
relink_accounts();
- $form->error($locale->text('Cannot post invoice!'))
- unless IS->post_invoice(\%myconfig, \%$form);
+
+ # If transfer_out is requested, get rose db handle and do post and
+ # transfer out in one transaction. Otherwise just post the invoice.
+ if ($::instance_conf->get_is_transfer_out && $form->{type} ne 'credit_note' && !$form->{storno}) {
+ require SL::DB::Inventory;
+ my $rose_db = SL::DB::Inventory->new->db;
+ my @errors;
+
+ if (!$rose_db->with_transaction(sub {
+ if (!eval {
+ if (!IS->post_invoice(\%myconfig, \%$form, $rose_db->dbh)) {
+ push @errors, $locale->text('Cannot post invoice!');
+ die 'posting error';
+ }
+ my $err = IS->transfer_out(\%$form, $rose_db->dbh);
+ if (@{ $err }) {
+ push @errors, @{ $err };
+ die 'transfer error';
+ }
+
+ 1;
+ }) {
+ push @errors, $EVAL_ERROR;
+ die 'transaction error';
+ }
+
+ 1;
+ })) {
+ push @errors, $rose_db->error;
+ $form->error($locale->text('Cannot post invoice and/or transfer out! Error message:') . "\n" . join("\n", @errors));
+ }
+ } else {
+ if (!IS->post_invoice(\%myconfig, \%$form)) {
+ $form->error($locale->text('Cannot post invoice!'));
+ }
+ }
+
remove_draft() if $form->{remove_draft};
if(!exists $form->{addition}) {
$main::auth->assert('invoice_edit');
- delete @{ $form }{qw(printed emailed queued invnumber invdate deliverydate id datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno locked)};
- $form->{paidaccounts} = 1;
+ delete @{ $form }{qw(printed emailed queued invnumber invdate exchangerate forex deliverydate id datepaid_1 gldate_1 acc_trans_id_1 source_1 memo_1 paid_1 exchangerate_1 AP_paid_1 storno locked)};
$form->{rowcount}--;
- $form->{invdate} = $form->current_date(\%myconfig);
- $form->{duedate} = $form->get_duedate(\%myconfig, $form->{invdate}) || $form->{invdate};
- $form->{employee_id} = SL::DB::Manager::Employee->current->id;
+ $form->{paidaccounts} = 1;
+ $form->{invdate} = $form->current_date(\%myconfig);
+ $form->{duedate} = $form->get_duedate(\%myconfig, $form->{invdate}) || $form->{invdate};
+ $form->{employee_id} = SL::DB::Manager::Employee->current->id;
+ $form->{forex} = $form->check_exchangerate(\%myconfig, $form->{currency}, $form->{invdate}, 'buy');
+ $form->{exchangerate} = $form->{forex} if $form->{forex};
- # remember pricegroups for "use as new"
- IS->get_pricegroups_for_parts(\%myconfig, \%$form);
- set_pricegroup($_) for 1 .. $form->{rowcount};
+ $form->{"converted_from_invoice_id_$_"} = delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
+ $form->{useasnew} = 1;
&display_form;
$main::lxdebug->leave_sub();
$form->error($locale->text('Cannot storno invoice for a closed period!'));
}
+ # save the history of invoice being stornoed
+ $form->{snumbers} = qq|invnumber_| . $form->{invnumber};
+ $form->{addition} = "STORNO";
+ $form->save_history;
+
map({ my $key = $_; delete($form->{$key}) unless (grep({ $key eq $_ } qw(id login password type))); } keys(%{ $form }));
invoice_links();
$form->{invnumber} = "Storno zu " . $form->{invnumber};
$form->{invdate} = DateTime->today->to_lxoffice;
$form->{rowcount}++;
+ # set new ids for storno invoice
+ delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
post();
$main::lxdebug->leave_sub();
$form->{duedate} =
$form->current_date(\%myconfig, $form->{invdate}, $form->{terms} * 1);
+ $form->{convert_from_ar_ids} = $form->{id};
$form->{id} = '';
$form->{rowcount}--;
- $form->{shipto} = 1;
$form->{title} = $locale->text('Add Credit Note');
$form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"}) if $form->{"${_}_${i}"};
}
}
+ # set new persistent ids for credit note and link previous invoice id
+ $form->{"converted_from_invoice_id_$_"} = delete $form->{"invoice_id_$_"} for 1 .. $form->{"rowcount"};
my $currency = $form->{currency};
&invoice_links;