X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=bin%2Fmozilla%2Foe.pl;h=11e220a68f499be6bd2a7b4e206c01f5a7c52a77;hb=9093d62e4e9e540618daf66cdb6e7a53ad75b2d5;hp=e59e95c8faf67e0c9acec90dc49c602148059d50;hpb=f48af81769e3a7da01d09ff63e61dbd09fe5ad2e;p=kivitendo-erp.git diff --git a/bin/mozilla/oe.pl b/bin/mozilla/oe.pl index e59e95c8f..11e220a68 100644 --- a/bin/mozilla/oe.pl +++ b/bin/mozilla/oe.pl @@ -35,15 +35,16 @@ use Carp; use POSIX qw(strftime); +use SL::DB::Order; use SL::DO; use SL::FU; use SL::OE; use SL::IR; use SL::IS; -use SL::MoreCommon qw(ary_diff); +use SL::MoreCommon qw(ary_diff restore_form save_form); use SL::PE; use SL::ReportGenerator; -use List::MoreUtils qw(any none); +use List::MoreUtils qw(uniq any none); use List::Util qw(min max reduce sum); use Data::Dumper; @@ -89,6 +90,16 @@ sub check_oe_access { $main::auth->assert($right); } +sub check_oe_conversion_to_sales_invoice_allowed { + return 1 if $::form->{type} !~ m/^sales/; + return 1 if ($::form->{type} =~ m/quotation/) && $::instance_conf->get_allow_sales_invoice_from_sales_quotation; + return 1 if ($::form->{type} =~ m/order/) && $::instance_conf->get_allow_sales_invoice_from_sales_order; + + $::form->show_generic_error($::locale->text("You do not have the permissions to access this function.")); + + return 0; +} + sub set_headings { $main::lxdebug->enter_sub(); @@ -144,6 +155,8 @@ sub add { "$form->{script}?action=add&type=$form->{type}&vc=$form->{vc}" unless $form->{callback}; + $form->{show_details} = $::myconfig{show_form_details}; + &order_links; &prepare_order; &display_form; @@ -158,6 +171,7 @@ sub edit { check_oe_access(); + $form->{show_details} = $::myconfig{show_form_details}; $form->{taxincluded_changed_by_user} = 1; # show history button @@ -230,8 +244,6 @@ sub order_links { $form->all_vc(\%myconfig, $form->{vc}, ($form->{vc} eq 'customer') ? "AR" : "AP"); # retrieve order/quotation - $form->{webdav} = $::instance_conf->get_webdav; - my $editing = $form->{id}; OE->retrieve(\%myconfig, \%$form); @@ -246,7 +258,6 @@ sub order_links { $form->{"$form->{vc}_id"} ||= $form->{"all_$form->{vc}"}->[0]->{id} if $form->{"all_$form->{vc}"}; $form->backup_vars(qw(payment_id language_id taxzone_id salesman_id taxincluded cp_id intnotes shipto_id delivery_term_id currency)); - $form->{shipto} = 1 if $form->{id} || $form->{convert_from_oe_ids}; # get customer / vendor IR->get_vendor(\%myconfig, \%$form) if $form->{type} =~ /(purchase_order|request_quotation)/; @@ -312,6 +323,18 @@ sub form_header { # Container for template variables. Unfortunately this has to be # visible in form_footer too, so package local level and not my here. %TMPL_VAR = (); + if ($form->{id}) { + my $obj = SL::DB::Order->new(id => $form->{id})->load; + $TMPL_VAR{warn_save_active_periodic_invoice} = + $obj->is_type('sales_order') + && $obj->periodic_invoices_config + && $obj->periodic_invoices_config->active + && ( !$obj->periodic_invoices_config->end_date + || ($obj->periodic_invoices_config->end_date > DateTime->today_local)) + && $obj->periodic_invoices_config->get_previous_billed_period_start_date; + + $TMPL_VAR{oe_obj} = $obj; + } $form->{defaultcurrency} = $form->get_default_currency(\%myconfig); @@ -321,19 +344,14 @@ sub form_header { # openclosed checkboxes my @tmp; push @tmp, sprintf qq||, - $form->{"delivered"} ? "checked" : "", $locale->text('Delivery Order created') if $form->{"type"} =~ /_order$/; + $form->{"delivered"} ? "checked" : "", $locale->text('Delivery Order(s) for full qty created') if $form->{"type"} =~ /_order$/; push @tmp, sprintf qq||, $form->{"closed"} ? "checked" : "", $locale->text('Closed') if $form->{id}; $TMPL_VAR{openclosed} = sprintf qq|%s\n|, 2 * scalar @tmp, join "\n", @tmp if @tmp; - # project ids - my @old_project_ids = ($form->{"globalproject_id"}, grep { $_ } map { $form->{"project_id_$_"} } 1..$form->{"rowcount"}); - my $vc = $form->{vc} eq "customer" ? "customers" : "vendors"; - $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"), "payments" => "ALL_PAYMENTS", "currencies" => "ALL_CURRENCIES", "departments" => "ALL_DEPARTMENTS", @@ -341,6 +359,26 @@ sub form_header { limit => $myconfig{vclimit} + 1 }, "price_factors" => "ALL_PRICE_FACTORS"); + # 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 (($vc eq 'customers') && $::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); + $form->{ALL_PROJECTS} = $TMPL_VAR{ALL_PROJECTS}; # make projects available for second row drop-down in io.pl + # label subs my $employee_list_query_gen = sub { $::form->{$_[0]} ? [ or => [ id => $::form->{$_[0]}, deleted => 0 ] ] : [ deleted => 0 ] }; $TMPL_VAR{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all_sorted(query => $employee_list_query_gen->('employee_id')); @@ -429,20 +467,23 @@ sub form_header { } } - $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.SalesPurchase show_form_details show_history show_vc_details)); + $::request->{layout}->use_javascript(map { "${_}.js" } qw(kivi.SalesPurchase show_form_details show_history show_vc_details ckeditor/ckeditor ckeditor/adapters/jquery kivi.io autocomplete_customer autocomplete_part)); $form->header; if ($form->{CFDD_shipto} && $form->{CFDD_shipto_id} ) { $form->{shipto_id} = $form->{CFDD_shipto_id}; } + + push @custom_hiddens, map { "shiptocvar_" . $_->name } @{ SL::DB::Manager::CustomVariableConfig->get_all(where => [ module => 'ShipTo' ]) }; + $TMPL_VAR{HIDDENS} = [ map { name => $_, value => $form->{$_} }, qw(id action type vc formname media format proforma queued printed emailed title creditlimit creditremaining tradediscount business max_dunning_level dunning_amount shiptoname shiptostreet shiptozipcode - CFDD_shipto CFDD_shipto_id shiptocity shiptocountry shiptocontact shiptophone shiptofax + CFDD_shipto CFDD_shipto_id shiptocity shiptocountry shiptogln shiptocontact shiptophone shiptofax shiptodepartment_1 shiptodepartment_2 shiptoemail shiptocp_gender message email subject cc bcc taxpart taxservice taxaccounts cursor_fokus - show_details), + show_details useasnew), @custom_hiddens, map { $_.'_rate', $_.'_description', $_.'_taxnumber' } split / /, $form->{taxaccounts} ]; # deleted: discount @@ -456,6 +497,8 @@ sub form_header { is_pur_ord => scalar ($form->{type} =~ /purchase_order$/), ); + $TMPL_VAR{ORDER_PROBABILITIES} = [ map { { title => ($_ * 10) . '%', id => $_ * 10 } } (0..10) ]; + print $form->parse_html_template("oe/form_header", { %TMPL_VAR }); $main::lxdebug->leave_sub(); @@ -472,11 +515,9 @@ sub form_footer { $form->{invtotal} = $form->{invsubtotal}; - my $rows = max 2, $form->numtextrows($form->{notes}, 25, 8); - my $introws = max 2, $form->numtextrows($form->{intnotes}, 35, 8); - $rows = max $rows, $introws; + my $introws = max 5, $form->numtextrows($form->{intnotes}, 35, 8); - $TMPL_VAR{notes} = qq||; + $TMPL_VAR{notes} = qq||; $TMPL_VAR{intnotes} = qq||; if( $form->{customer_id} && !$form->{taxincluded_changed_by_user} ) { @@ -498,9 +539,6 @@ sub form_footer { |; } } - -# $form->{invsubtotal} = $form->format_amount(\%myconfig, $form->{invsubtotal}, 2, 0); # template does this - } else { foreach my $item (split / /, $form->{taxaccounts}) { if ($form->{"${item}_base"}) { @@ -522,13 +560,19 @@ sub form_footer { } } + $form->{rounding} = $form->round_amount( + $form->round_amount($form->{invtotal}, 2, 1) - $form->round_amount($form->{invtotal}, 2) + ); + $form->{invtotal} = $form->round_amount( $form->{invtotal}, 2, 1); $form->{oldinvtotal} = $form->{invtotal}; $TMPL_VAR{ALL_DELIVERY_TERMS} = SL::DB::Manager::DeliveryTerm->get_all_sorted(); + my $tpca_reminder; + $tpca_reminder = check_transport_cost_reminder_article_number() if $::instance_conf->get_transport_cost_reminder_article_number_id; print $form->parse_html_template("oe/form_footer", { %TMPL_VAR, - webdav => $::instance_conf->get_webdav, + tpca_reminder => $tpca_reminder, print_options => print_options(inline => 1), label_edit => $locale->text("Edit the $form->{type}"), label_workflow => $locale->text("Workflow $form->{type}"), @@ -592,11 +636,8 @@ sub update { my $rows = scalar @{ $form->{item_list} }; - # hier ist das problem fuer bug 817 $form->{discount} wird nicht durchgeschliffen - # ferner fallunterscheidung fuer verkauf oder einkauf s.a. bug 736 jb 04.05.2009 - # select discount as vendor_discount from vendor || - # select discount as customer_discount from customer - $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"$form->{vc}_discount"} * 100); + $form->{"discount_$i"} = $form->parse_amount(\%myconfig, $form->{"discount_$i"}) / 100.0; + $form->{"discount_$i"} ||= $form->{"$form->{vc}_discount"}; $form->{"lastcost_$i"} = $form->parse_amount(\%myconfig, $form->{"lastcost_$i"}); @@ -609,8 +650,8 @@ sub update { if ($rows > 1) { - select_item(mode => $mode); - ::end_of_request(); + select_item(mode => $mode, pre_entered_qty => $form->{"qty_$i"}); + $::dispatcher->end_request; } else { @@ -637,11 +678,24 @@ sub update { if ($sellprice) { $form->{"sellprice_$i"} = $sellprice; } else { - $form->{"sellprice_$i"} *= (1 - $form->{tradediscount}); + 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; + } + $form->{"sellprice_$i"} /= $exchangerate; # if there is an exchange rate adjust sellprice } - 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} if !$form->{taxincluded}; @@ -651,12 +705,7 @@ sub update { $form->{"sellprice_$i"} = $form->format_amount(\%myconfig, $form->{"sellprice_$i"}, $decimalplaces); $form->{"lastcost_$i"} = $form->format_amount(\%myconfig, $form->{"lastcost_$i"}, $decimalplaces); $form->{"qty_$i"} = $form->format_amount(\%myconfig, $form->{"qty_$i"}, $dec_qty); - - # get pricegroups for parts - IS->get_pricegroups_for_parts(\%myconfig, \%$form); - - # build up html code for prices_$i - &set_pricegroup($i); + $form->{"discount_$i"} = $form->format_amount(\%myconfig, $form->{"discount_$i"} * 100.0); } display_form(); @@ -730,13 +779,20 @@ sub search { "business_types" => "ALL_BUSINESS_TYPES",); $form->{ALL_EMPLOYEES} = SL::DB::Manager::Employee->get_all_sorted(query => [ deleted => 0 ]); + $form->{CT_CUSTOM_VARIABLES} = CVar->get_configs('module' => 'CT'); + ($form->{CT_CUSTOM_VARIABLES_FILTER_CODE}, + $form->{CT_CUSTOM_VARIABLES_INCLUSION_CODE}) = CVar->render_search_options('variables' => $form->{CT_CUSTOM_VARIABLES}, + 'include_prefix' => 'l_', + 'include_value' => 'Y'); + # constants and subs for template $form->{vc_keys} = sub { "$_[0]->{name}--$_[0]->{id}" }; + $form->{ORDER_PROBABILITIES} = [ map { { title => ($_ * 10) . '%', id => $_ * 10 } } (0..10) ]; + $form->header(); print $form->parse_html_template('oe/search', { - %myconfig, is_order => scalar($form->{type} =~ /_order/), }); @@ -786,7 +842,7 @@ sub orders { my @columns = ( "transdate", "reqdate", - "id", $ordnumber, + "id", $ordnumber, "edit_exp", "cusordnumber", "customernumber", "name", "netamount", "tax", "amount", @@ -799,7 +855,9 @@ sub orders { "marge_total", "marge_percent", "vcnumber", "ustid", "country", "shippingpoint", - "taxzone", + "taxzone", "insertdate", + "order_probability", "expected_billing_date", "expected_netamount", + "payment_terms", ); # only show checkboxes if gotten here via sales_order form. @@ -811,6 +869,8 @@ sub orders { $form->{l_open} = $form->{l_closed} = "Y" if ($form->{open} && $form->{closed}); $form->{l_delivered} = "Y" if ($form->{delivered} && $form->{notdelivered}); $form->{l_periodic_invoices} = "Y" if ($form->{periodic_invoices_active} && $form->{periodic_invoices_inactive}); + $form->{l_edit_exp} = "Y" if (any { $form->{type} eq $_ } qw(sales_order purchase_order)); + map { $form->{"l_${_}"} = 'Y' } qw(order_probability expected_billing_date expected_netamount) if $form->{l_order_probability_expected_billing_date}; my $attachment_basename; if ($form->{vc} eq 'vendor') { @@ -834,11 +894,21 @@ sub orders { my $report = SL::ReportGenerator->new(\%myconfig, $form); + my $ct_cvar_configs = CVar->get_configs('module' => 'CT'); + my @ct_includeable_custom_variables = grep { $_->{includeable} } @{ $ct_cvar_configs }; + my @ct_searchable_custom_variables = grep { $_->{searchable} } @{ $ct_cvar_configs }; + + my %column_defs_cvars = map { +"cvar_$_->{name}" => { 'text' => $_->{description} } } @ct_includeable_custom_variables; + push @columns, map { "cvar_$_->{name}" } @ct_includeable_custom_variables; + my @hidden_variables = map { "l_${_}" } @columns; push @hidden_variables, "l_subtotal", $form->{vc}, qw(l_closed l_notdelivered open closed delivered notdelivered ordnumber quonumber cusordnumber transaction_description transdatefrom transdateto type vc employee_id salesman_id reqdatefrom reqdateto projectnumber project_id periodic_invoices_active periodic_invoices_inactive - business_id shippingpoint taxzone_id); + business_id shippingpoint taxzone_id reqdate_unset_or_old insertdatefrom insertdateto + order_probability_op order_probability_value expected_billing_date_from expected_billing_date_to + parts_partnumber parts_description); + push @hidden_variables, map { "cvar_$_->{name}" } @ct_searchable_custom_variables; my @keys_for_url = grep { $form->{$_} } @hidden_variables; push @keys_for_url, 'taxzone_id' if $form->{taxzone_id} ne ''; # taxzone_id could be 0 @@ -876,14 +946,21 @@ sub orders { 'periodic_invoices' => { 'text' => $locale->text('Per. Inv.'), }, 'shippingpoint' => { 'text' => $locale->text('Shipping Point'), }, 'taxzone' => { 'text' => $locale->text('Steuersatz'), }, + 'insertdate' => { 'text' => $locale->text('Insert Date'), }, + 'order_probability' => { 'text' => $locale->text('Order probability'), }, + 'expected_billing_date' => { 'text' => $locale->text('Exp. bill. date'), }, + 'expected_netamount' => { 'text' => $locale->text('Exp. netamount'), }, + 'payment_terms' => { 'text' => $locale->text('Payment Terms'), }, + 'edit_exp' => { 'text' => $locale->text('Edit (experimental)'), }, + %column_defs_cvars, ); - foreach my $name (qw(id transdate reqdate quonumber ordnumber cusordnumber name employee salesman shipvia transaction_description shippingpoint taxzone)) { + foreach my $name (qw(id transdate reqdate quonumber ordnumber cusordnumber name employee salesman shipvia transaction_description shippingpoint taxzone insertdate payment_terms)) { my $sortdir = $form->{sort} eq $name ? 1 - $form->{sortdir} : $form->{sortdir}; $column_defs{$name}->{link} = $href . "&sort=$name&sortdir=$sortdir"; } - my %column_alignment = map { $_ => 'right' } qw(netamount tax amount curr remaining_amount remaining_netamount); + my %column_alignment = map { $_ => 'right' } qw(netamount tax amount curr remaining_amount remaining_netamount order_probability expected_billing_date expected_netamount); $form->{"l_type"} = "Y"; map { $column_defs{$_}->{visible} = $form->{"l_${_}"} ? 1 : 0 } @columns; @@ -894,17 +971,27 @@ sub orders { $report->set_export_options('orders', @hidden_variables, qw(sort sortdir)); $report->set_sort_indicator($form->{sort}, $form->{sortdir}); + CVar->add_custom_variables_to_report('module' => 'CT', + 'trans_id_field' => "$form->{vc}_id", + 'configs' => $ct_cvar_configs, + 'column_defs' => \%column_defs, + 'data' => $form->{OE}); + my @options; my ($department) = split m/--/, $form->{department}; push @options, $locale->text('Customer') . " : $form->{customer}" if $form->{customer}; push @options, $locale->text('Vendor') . " : $form->{vendor}" if $form->{vendor}; + push @options, $locale->text('Contact Person') . " : $form->{cp_name}" if $form->{cp_name}; push @options, $locale->text('Department') . " : $department" if $form->{department}; push @options, $locale->text('Order Number') . " : $form->{ordnumber}" if $form->{ordnumber}; push @options, $locale->text('Customer Order Number') . " : $form->{cusordnumber}" if $form->{cusordnumber}; push @options, $locale->text('Notes') . " : $form->{notes}" if $form->{notes}; push @options, $locale->text('Transaction description') . " : $form->{transaction_description}" if $form->{transaction_description}; + push @options, $locale->text('Quick Search') . " : $form->{all}" if $form->{all}; push @options, $locale->text('Shipping Point') . " : $form->{shippingpoint}" if $form->{shippingpoint}; + push @options, $locale->text('Part Description') . " : $form->{parts_description}" if $form->{parts_description}; + push @options, $locale->text('Part Number') . " : $form->{parts_partnumber}" if $form->{parts_partnumber}; if ( $form->{transdatefrom} or $form->{transdateto} ) { push @options, $locale->text('Order Date'); push @options, $locale->text('From') . " " . $locale->date(\%myconfig, $form->{transdatefrom}, 1) if $form->{transdatefrom}; @@ -915,11 +1002,17 @@ sub orders { push @options, $locale->text('From') . " " . $locale->date(\%myconfig, $form->{reqdatefrom}, 1) if $form->{reqdatefrom}; push @options, $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{reqdateto}, 1) if $form->{reqdateto}; }; + if ( $form->{insertdatefrom} or $form->{insertdateto} ) { + push @options, $locale->text('Insert Date'); + push @options, $locale->text('From') . " " . $locale->date(\%myconfig, $form->{insertdatefrom}, 1) if $form->{insertdatefrom}; + push @options, $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{insertdateto}, 1) if $form->{insertdateto}; + }; push @options, $locale->text('Open') if $form->{open}; push @options, $locale->text('Closed') if $form->{closed}; push @options, $locale->text('Delivery Order created') if $form->{delivered}; push @options, $locale->text('Not delivered') if $form->{notdelivered}; push @options, $locale->text('Periodic invoices active') if $form->{periodic_invoices_active}; + push @options, $locale->text('Reqdate not set or before current month') if $form->{reqdate_unset_or_old}; if ($form->{business_id}) { my $vc_type_label = $form->{vc} eq 'customer' ? $locale->text('Customer type') : $locale->text('Vendor type'); @@ -929,6 +1022,16 @@ sub orders { push @options, $locale->text('Steuersatz') . " : " . SL::DB::TaxZone->new(id => $form->{taxzone_id})->load->description; } + if (($form->{order_probability_value} || '') ne '') { + push @options, $::locale->text('Order probability') . ' ' . ($form->{order_probability_op} eq 'le' ? '<=' : '>=') . ' ' . $form->{order_probability_value} . '%'; + } + + if ($form->{expected_billing_date_from} or $form->{expected_billing_date_to}) { + push @options, $locale->text('Expected billing date'); + push @options, $locale->text('From') . " " . $locale->date(\%myconfig, $form->{expected_billing_date_from}, 1) if $form->{expected_billing_date_from}; + push @options, $locale->text('Bis') . " " . $locale->date(\%myconfig, $form->{expected_billing_date_to}, 1) if $form->{expected_billing_date_to}; + } + $report->set_options('top_info_text' => join("\n", @options), 'raw_top_info_text' => $form->parse_html_template('oe/orders_top'), 'raw_bottom_info_text' => $form->parse_html_template('oe/orders_bottom', { 'SHOW_CONTINUE_BUTTON' => $allow_multiple_orders }), @@ -946,6 +1049,7 @@ sub orders { my $callback = $form->escape($href); my @subtotal_columns = qw(netamount amount marge_total marge_percent remaining_amount remaining_netamount); + push @subtotal_columns, 'expected_netamount' if $form->{l_order_probability_expected_billing_date}; my %totals = map { $_ => 0 } @subtotal_columns; my %subtotals = map { $_ => 0 } @subtotal_columns; @@ -968,12 +1072,15 @@ sub orders { $subtotals{marge_percent} = $subtotals{netamount} ? ($subtotals{marge_total} * 100 / $subtotals{netamount}) : 0; $totals{marge_percent} = $totals{netamount} ? ($totals{marge_total} * 100 / $totals{netamount} ) : 0; - map { $oe->{$_} = $form->format_amount(\%myconfig, $oe->{$_}, 2) } qw(netamount tax amount marge_total marge_percent remaining_amount remaining_netamount); + map { $oe->{$_} = $form->format_amount(\%myconfig, $oe->{$_}, 2) } qw(netamount tax amount marge_total marge_percent remaining_amount remaining_netamount expected_netamount); + + $oe->{order_probability} = ($oe->{order_probability} || 0) . '%'; my $row = { }; foreach my $column (@columns) { next if ($column eq 'ids'); + next if ($column eq 'edit_exp'); $row->{$column} = { 'data' => $oe->{$column}, 'align' => $column_alignment{$column}, @@ -989,6 +1096,9 @@ sub orders { $row->{$ordnumber}->{link} = $edit_url . "&id=" . E($oe->{id}) . "&callback=${callback}"; + $row->{edit_exp}->{data} = $oe->{ordnumber}; + $row->{edit_exp}->{link} = build_std_url('script=controller.pl', 'action=Order/edit', "type=$form->{type}", 'id=' . E($oe->{id})); + my $row_set = [ $row ]; if (($form->{l_subtotal} eq 'Y') @@ -1049,6 +1159,7 @@ sub save_and_close { my $locale = $main::locale; check_oe_access(); + $form->mtime_ischanged('oe'); $form->{defaultcurrency} = $form->get_default_currency(\%myconfig); @@ -1084,7 +1195,7 @@ sub save_and_close { $form->{payment_id} = $payment_id; } &update; - ::end_of_request(); + $::dispatcher->end_request; } $form->{id} = 0 if $form->{saveasnew}; @@ -1155,6 +1266,7 @@ sub save { check_oe_access(); + $form->mtime_ischanged('oe'); $form->{defaultcurrency} = $form->get_default_currency(\%myconfig); @@ -1191,7 +1303,7 @@ sub save { $form->{payment_id} = $payment_id; } &update; - ::end_of_request(); + $::dispatcher->end_request; } $form->{id} = 0 if $form->{saveasnew}; @@ -1254,7 +1366,7 @@ sub save { if(!$form->{print_and_save}) { delete @{$form}{ary_diff([keys %{ $form }], [qw(login id script type cursor_fokus)])}; edit(); - ::end_of_request(); + $::dispatcher->end_request; } $main::lxdebug->leave_sub(); } @@ -1279,13 +1391,18 @@ sub delete { if (OE->delete(\%myconfig, \%$form)){ # saving the history if(!exists $form->{addition}) { - $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber}; - $form->{addition} = "DELETED"; - $form->save_history; + if ( $form->{formname} eq 'sales_quotation' or $form->{formname} eq 'request_quotation' ) { + $form->{snumbers} = qq|quonumber_| . $form->{quonumber}; + } elsif ( $form->{formname} eq 'sales_order' or $form->{formname} eq 'purchase_order') { + $form->{snumbers} = qq|ordnumber_| . $form->{ordnumber}; + }; + $form->{what_done} = $form->{formname}; + $form->{addition} = "DELETED"; + $form->save_history; } # /saving the history $form->info($msg); - ::end_of_request(); + $::dispatcher->end_request; } $form->error($err); @@ -1300,6 +1417,9 @@ sub invoice { my $locale = $main::locale; check_oe_access(); + check_oe_conversion_to_sales_invoice_allowed(); + $form->mtime_ischanged('oe'); + $main::auth->assert($form->{type} eq 'purchase_order' || $form->{type} eq 'request_quotation' ? 'vendor_invoice_edit' : 'invoice_edit'); $form->{old_salesman_id} = $form->{salesman_id}; @@ -1334,7 +1454,7 @@ sub invoice { if (&check_name($form->{vc})) { $form->{payment_id} = $payment_id if $form->{payment_id} eq ""; &update; - ::end_of_request(); + $::dispatcher->end_request; } _oe_remove_delivered_or_billed_rows(id => $form->{id}, type => 'billed'); @@ -1342,9 +1462,10 @@ sub invoice { $form->{cp_id} *= 1; for my $i (1 .. $form->{rowcount}) { - for (qw(ship qty sellprice listprice basefactor)) { + for (qw(ship qty sellprice basefactor)) { $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"}) if $form->{"${_}_${i}"}; } + $form->{"converted_from_orderitems_id_$i"} = delete $form->{"orderitems_id_$i"}; } my ($buysell, $orddate, $exchangerate); @@ -1365,17 +1486,11 @@ sub invoice { $form->{convert_from_oe_ids} = $form->{id}; $form->{transdate} = $form->{invdate} = $form->current_date(\%myconfig); $form->{duedate} = $form->current_date(\%myconfig, $form->{invdate}, $form->{terms} * 1); - $form->{shipto} = 1; $form->{defaultcurrency} = $form->get_default_currency(\%myconfig); delete @{$form}{qw(id closed)}; $form->{rowcount}--; - if ($form->{type} =~ /_order$/) { - $form->{exchangerate} = $exchangerate; - &create_backorder; - } - my ($script); if ( $form->{type} eq 'purchase_order' || $form->{type} eq 'request_quotation') { @@ -1399,7 +1514,7 @@ sub invoice { $form->{type} = "invoice"; # locale messages - $main::locale = new Locale "$myconfig{countrycode}", "$script"; + $main::locale = Locale->new("$myconfig{countrycode}", "$script"); $locale = $main::locale; require "bin/mozilla/$form->{script}"; @@ -1440,10 +1555,6 @@ sub invoice { $form->format_amount(\%myconfig, $form->{"qty_$i"}, $dec_qty); } - # show pricegroup in newly loaded invoice when creating invoice from quotation/order - IS->get_pricegroups_for_parts(\%myconfig, \%$form); - set_pricegroup($_) for 1 .. $form->{rowcount}; - &display_form; $main::lxdebug->leave_sub(); @@ -1468,76 +1579,6 @@ sub save_exchangerate { $main::lxdebug->leave_sub(); } -sub create_backorder { - $main::lxdebug->enter_sub(); - - my $form = $main::form; - my %myconfig = %main::myconfig; - - $form->{shipped} = 1; - - # figure out if we need to create a backorder - # items aren't saved if qty != 0 - - my ($totalqty, $totalship); - for my $i (1 .. $form->{rowcount}) { - my $qty = $form->{"qty_$i"}; - my $ship = $form->{"ship_$i"}; - $totalqty += $qty; - $totalship += $ship; - - $form->{"qty_$i"} = $qty - $ship; - } - - if ($totalship == 0) { - map { $form->{"ship_$_"} = $form->{"qty_$_"} } (1 .. $form->{rowcount}); - $form->{ordtotal} = 0; - $form->{shipped} = 0; - return; - } - - if ($totalqty == $totalship) { - map { $form->{"qty_$_"} = $form->{"ship_$_"} } (1 .. $form->{rowcount}); - $form->{ordtotal} = 0; - return; - } - - my @flds = ( - qw(partnumber description qty ship unit sellprice discount id inventory_accno bin income_accno expense_accno listprice assembly taxaccounts partsgroup) - ); - - for my $i (1 .. $form->{rowcount}) { - map { - $form->{"${_}_$i"} = - $form->format_amount(\%myconfig, $form->{"${_}_$i"}) - } qw(sellprice discount); - } - - relink_accounts(); - - OE->save(\%myconfig, \%$form); - - # rebuild rows for invoice - my @a = (); - my $count = 0; - - for my $i (1 .. $form->{rowcount}) { - $form->{"qty_$i"} = $form->{"ship_$i"}; - - if ($form->{"qty_$i"}) { - push @a, {}; - my $j = $#a; - map { $a[$j]->{$_} = $form->{"${_}_$i"} } @flds; - $count++; - } - } - - $form->redo_rows(\@flds, \@a, $count, $form->{rowcount}); - $form->{rowcount} = $count; - - $main::lxdebug->leave_sub(); -} - sub save_as_new { $main::lxdebug->enter_sub(); @@ -1547,6 +1588,7 @@ sub save_as_new { $form->{saveasnew} = 1; map { delete $form->{$_} } qw(printed emailed queued delivered closed); + $form->{"converted_from_orderitems_id_$_"} = delete $form->{"orderitems_id_$_"} for 1 .. $form->{"rowcount"}; # Let kivitendo assign a new order number if the user hasn't changed the # previous one. If it has been changed manually then use it as-is. @@ -1562,21 +1604,9 @@ sub save_as_new { if ( $form->{reqdate} && $form->{id} ) { my $saved_order = OE->retrieve_simple(id => $form->{id}); if ( $saved_order && $saved_order->{reqdate} eq $form->{reqdate} && $saved_order->{transdate} eq $form->{transdate} ) { - - my $dbh = $form->get_standard_dbh; - - my $wday = (localtime(time))[6]; - my $next_workday = $wday == 5 ? 3 : $wday == 6 ? 2 : 1; - - my $query = 'SELECT - date(current_date + interval \''. $next_workday .' days\') AS reqdate, - date(current_date) AS transdate'; - my $ref = selectfirst_hashref_query($form, $dbh, $query); - - map( - { $form->{$_} = $ref->{$_} } - keys %{$ref} - ); + my $extra_days = $form->{type} eq 'sales_quotation' ? $::instance_conf->get_reqdate_interval : 1; + $form->{reqdate} = DateTime->today_local->next_workday(extra_days => $extra_days)->to_kivitendo; + $form->{transdate} = DateTime->today_local->to_kivitendo; } } @@ -1598,7 +1628,6 @@ sub check_for_direct_delivery_yes { $form->{direct_delivery_checked} = 1; delete @{$form}{grep /^shipto/, keys %{ $form }}; map { s/^CFDD_//; $form->{$_} = $form->{"CFDD_${_}"} } grep /^CFDD_/, keys %{ $form }; - $form->{shipto} = 1; $form->{CFDD_shipto} = 1; purchase_order(); $main::lxdebug->leave_sub(); @@ -1633,6 +1662,8 @@ sub check_for_direct_delivery { return; } + my $cvars = SL::DB::Shipto->new->cvars_by_config; + if ($form->{shipto_id}) { Common->get_shipto_by_id(\%myconfig, $form, $form->{shipto_id}, "CFDD_"); @@ -1640,15 +1671,17 @@ sub check_for_direct_delivery { map { $form->{"CFDD_${_}"} = $form->{$_ } } grep /^shipto/, keys %{ $form }; } + $_->value($::form->{"CFDD_shiptocvar_" . $_->config->name}) for @{ $cvars }; + delete $form->{action}; $form->{VARIABLES} = [ map { { "key" => $_, "value" => $form->{$_} } } grep { ($_ ne 'login') && ($_ ne 'password') && (ref $_ eq "") } keys %{ $form } ]; $form->header(); - print $form->parse_html_template("oe/check_for_direct_delivery"); + print $form->parse_html_template("oe/check_for_direct_delivery", { cvars => $cvars }); $main::lxdebug->leave_sub(); - ::end_of_request(); + $::dispatcher->end_request; } sub purchase_order { @@ -1658,6 +1691,8 @@ sub purchase_order { my $locale = $main::locale; check_oe_access(); + $form->mtime_ischanged('oe'); + $main::auth->assert('purchase_order_edit'); $form->{sales_order_to_purchase_order} = 0; @@ -1668,6 +1703,8 @@ sub purchase_order { if ($form->{type} =~ /^sales_/) { delete($form->{ordnumber}); + delete($form->{payment_id}); + delete($form->{delivery_term_id}); } $form->{cp_id} *= 1; @@ -1694,9 +1731,11 @@ sub sales_order { check_oe_access(); $main::auth->assert('sales_order_edit'); + $form->mtime_ischanged('oe'); if ($form->{type} eq "purchase_order") { delete($form->{ordnumber}); + $form->{"lastcost_$_"} = $form->{"sellprice_$_"} for (1..$form->{rowcount}); } $form->{cp_id} *= 1; @@ -1739,6 +1778,8 @@ sub poso { # reset map { delete $form->{$_} } qw(id subject message cc bcc printed emailed queued customer vendor creditlimit creditremaining discount tradediscount oldinvtotal delivered ordnumber); + # this converted variable is also used for sales_order to purchase order and vice versa + $form->{"converted_from_orderitems_id_$_"} = delete $form->{"orderitems_id_$_"} for 1 .. $form->{"rowcount"}; # if purchase_order was generated from sales_order, use lastcost_$i as sellprice_$i # also reset discounts @@ -1750,7 +1791,7 @@ sub poso { }; for my $i (1 .. $form->{rowcount}) { - map { $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"}) if ($form->{"${_}_${i}"}) } qw(ship qty sellprice listprice basefactor discount lastcost); + map { $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"}) if ($form->{"${_}_${i}"}) } qw(ship qty sellprice basefactor discount lastcost); } my %saved_vars = map { $_ => $form->{$_} } grep { $form->{$_} } qw(currency); @@ -1780,6 +1821,8 @@ sub delivery_order { my $form = $main::form; my %myconfig = %main::myconfig; + $form->mtime_ischanged('oe'); + if ($form->{type} =~ /^sales/) { $main::auth->assert('sales_delivery_order_edit'); @@ -1812,7 +1855,8 @@ sub delivery_order { delete @{$form}{qw(id subject message cc bcc printed emailed queued creditlimit creditremaining discount tradediscount oldinvtotal closed delivered)}; for my $i (1 .. $form->{rowcount}) { - map { $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"}) if ($form->{"${_}_${i}"}) } qw(ship qty sellprice listprice lastcost basefactor discount); + map { $form->{"${_}_${i}"} = $form->parse_amount(\%myconfig, $form->{"${_}_${i}"}) if ($form->{"${_}_${i}"}) } qw(ship qty sellprice lastcost basefactor discount); + $form->{"converted_from_orderitems_id_$i"} = delete $form->{"orderitems_id_$i"}; } my %old_values = map { $_ => $form->{$_} } qw(customer_id oldcustomer customer vendor_id oldvendor vendor shipto_id); @@ -1831,6 +1875,19 @@ sub delivery_order { $main::lxdebug->leave_sub(); } +sub oe_delivery_order_from_order { + + return if !$::form->{id}; + + my $order = SL::DB::Order->new(id => $::form->{id})->load; + $order->flatten_to_form($::form, format_amounts => 1); + + # fake last empty row + $::form->{rowcount}++; + + delivery_order(); +} + sub e_mail { $main::lxdebug->enter_sub(); @@ -1838,6 +1895,7 @@ sub e_mail { check_oe_access(); + $form->mtime_ischanged('oe','mail'); $form->{print_and_save} = 1; my $saved_form = save_form(); @@ -1929,14 +1987,16 @@ sub edit_periodic_invoices_config { $config = YAML::Load($::form->{periodic_invoices_config}) if $::form->{periodic_invoices_config}; if ('HASH' ne ref $config) { - $config = { periodicity => 'y', + $config = { periodicity => 'm', + order_value_periodicity => 'p', # = same as periodicity start_date_as_date => $::form->{transdate} || $::form->current_date, extend_automatically_by => 12, active => 1, }; } - $config->{periodicity} = 'm' if none { $_ eq $config->{periodicity} } qw(m q b y); + $config->{periodicity} = 'm' if none { $_ eq $config->{periodicity} } @SL::DB::PeriodicInvoicesConfig::PERIODICITIES; + $config->{order_value_periodicity} = 'p' if none { $_ eq $config->{order_value_periodicity} } ('p', @SL::DB::PeriodicInvoicesConfig::ORDER_VALUE_PERIODICITIES); $::form->get_lists(printers => "ALL_PRINTERS", charts => { key => 'ALL_CHARTS', @@ -1945,6 +2005,10 @@ sub edit_periodic_invoices_config { $::form->{AR} = [ grep { $_->{link} =~ m/(?:^|:)AR(?::|$)/ } @{ $::form->{ALL_CHARTS} } ]; $::form->{title} = $::locale->text('Edit the configuration for periodic invoices'); + if ($::form->{customer_id}) { + $::form->{ALL_CONTACTS} = SL::DB::Manager::Contact->get_all_sorted(where => [ cp_cv_id => $::form->{customer_id} ]); + } + $::form->header(no_layout => 1); print $::form->parse_html_template('oe/edit_periodic_invoices_config', $config); @@ -1962,7 +2026,9 @@ sub save_periodic_invoices_config { my $config = { active => $::form->{active} ? 1 : 0, terminated => $::form->{terminated} ? 1 : 0, - periodicity => (any { $_ eq $::form->{periodicity} } qw(m q b y)) ? $::form->{periodicity} : 'm', + direct_debit => $::form->{direct_debit} ? 1 : 0, + periodicity => (any { $_ eq $::form->{periodicity} } @SL::DB::PeriodicInvoicesConfig::PERIODICITIES) ? $::form->{periodicity} : 'm', + order_value_periodicity => (any { $_ eq $::form->{order_value_periodicity} } ('p', @SL::DB::PeriodicInvoicesConfig::ORDER_VALUE_PERIODICITIES)) ? $::form->{order_value_periodicity} : 'p', start_date_as_date => $::form->{start_date_as_date}, end_date_as_date => $::form->{end_date_as_date}, first_billing_date_as_date => $::form->{first_billing_date_as_date}, @@ -1971,6 +2037,12 @@ sub save_periodic_invoices_config { copies => $::form->{copies} * 1 ? $::form->{copies} : 1, extend_automatically_by => $::form->{extend_automatically_by} * 1 || undef, ar_chart_id => $::form->{ar_chart_id} * 1, + send_email => $::form->{send_email} ? 1 : 0, + email_recipient_contact_id => $::form->{email_recipient_contact_id} * 1 || undef, + email_recipient_address => $::form->{email_recipient_address}, + email_sender => $::form->{email_sender}, + email_subject => $::form->{email_subject}, + email_body => $::form->{email_body}, }; $::form->{periodic_invoices_config} = YAML::Dump($config); @@ -1982,6 +2054,34 @@ sub save_periodic_invoices_config { $::lxdebug->leave_sub(); } +sub _remove_full_delivered_rows { + + my @fields = map { s/_1$//; $_ } grep { m/_1$/ } keys %{ $::form }; + my @new_rows; + + my $removed_rows = 0; + my $row = 0; + while ($row < $::form->{rowcount}) { + $row++; + next unless $::form->{"id_$row"}; + my $base_factor = SL::DB::Manager::Unit->find_by(name => $::form->{"unit_$row"})->base_factor; + my $base_qty = $::form->parse_amount(\%::myconfig, $::form->{"qty_$row"}) * $base_factor; + my $ship_qty = $::form->parse_amount(\%::myconfig, $::form->{"ship_$row"}) * $base_factor; + #$main::lxdebug->message(LXDebug->DEBUG2(),"shipto=".$ship_qty." qty=".$base_qty); + + if (!$ship_qty || ($ship_qty < $base_qty)) { + $::form->{"qty_$row"} = $::form->format_amount(\%::myconfig, ($base_qty - $ship_qty) / $base_factor ); + $::form->{"ship_$row"} = 0; + push @new_rows, { map { $_ => $::form->{"${_}_${row}"} } @fields }; + + } else { + $removed_rows++; + } + } + $::form->redo_rows(\@fields, \@new_rows, scalar(@new_rows), $::form->{rowcount}); + $::form->{rowcount} -= $removed_rows; +} + sub _oe_remove_delivered_or_billed_rows { my (%params) = @_; @@ -1990,6 +2090,18 @@ sub _oe_remove_delivered_or_billed_rows { my $ord_quot = SL::DB::Order->new(id => $params{id})->load; return if !$ord_quot; + # Prüfung ob itemlinks existieren, falls ja dann neue Implementierung + + if ( $params{type} eq 'delivered' ) { + my $orderitem = SL::DB::Manager::OrderItem->get_first( where => [trans_id => $ord_quot->id]); + if ( $orderitem) { + my @links = $orderitem->linked_records(to => 'SL::DB::DeliveryOrderItem'); + if ( scalar(@links ) > 0 ) { + #$main::lxdebug->message(LXDebug->DEBUG2(),"item recordlinks vorhanden"); + return _remove_full_delivered_rows(); + } + } + } my %args = ( direction => 'to', to => $params{type} eq 'delivered' ? 'DeliveryOrder' : 'Invoice', @@ -2011,9 +2123,27 @@ sub _oe_remove_delivered_or_billed_rows { _remove_billed_or_delivered_rows(quantities => \%handled_base_qtys); } +# iterate all positions and match articlenumber +sub check_transport_cost_reminder_article_number { + $main::lxdebug->enter_sub(); + + my $form = $main::form; + + check_oe_access(); + + my $transport_article_id = $::instance_conf->get_transport_cost_reminder_article_number_id; + for my $i (1 .. $form->{rowcount}) { + return if $form->{"id_${i}"} eq $transport_article_id; + } + + # simply return the name of the part + return SL::DB::Part->new(id => $transport_article_id)->load()->partnumber; + + $main::lxdebug->leave_sub(); +} sub dispatcher { - foreach my $action (qw(delete delivery_order e_mail invoice print purchase_order purchase_order quotation - request_for_quotation sales_order sales_order save save_and_close save_as_new ship_to update)) { + foreach my $action (qw(delete delivery_order e_mail invoice print purchase_order quotation + request_for_quotation sales_order save save_and_close save_as_new ship_to update)) { if ($::form->{"action_${action}"}) { call_sub($action); return;