use Data::Dumper;
use List::MoreUtils qw(all any uniq);
-use YAML;
use SL::CVar;
use SL::DBUtils;
use SL::TransNumber;
use SL::Util qw(trim);
use SL::DB;
+use SL::Presenter::Part qw(type_abbreviation classification_abbreviation separate_abbreviation);
use Carp;
use strict;
-sub get_pricegroups {
- $main::lxdebug->enter_sub();
-
- my ($self, $myconfig, $form) = @_;
-
- my $dbh = $form->get_standard_dbh;
-
- # get pricegroups
- my $query = qq|SELECT id, pricegroup FROM pricegroup ORDER BY lower(pricegroup)|;
- my $pricegroups = selectall_hashref_query($form, $dbh, $query);
-
- my $i = 1;
- foreach my $pg (@{ $pricegroups }) {
- $form->{"price_$i"} = $form->format_amount($myconfig, $form->{"price_$i"}, -2);
- $form->{"pricegroup_id_$i"} = "$pg->{id}";
- $form->{"pricegroup_$i"} = "$pg->{pricegroup}";
- $i++;
- }
-
- #correct rows
- $form->{price_rows} = $i - 1;
-
- $main::lxdebug->leave_sub();
-
- return $pricegroups;
-}
-
sub retrieve_buchungsgruppen {
$main::lxdebug->enter_sub();
$main::lxdebug->leave_sub();
}
-
sub assembly_item {
$main::lxdebug->enter_sub();
#
# column flags:
# l_partnumber l_description l_listprice l_sellprice l_lastcost l_priceupdate l_weight l_unit l_rop l_image l_drawing l_microfiche l_partsgroup
+# l_warehouse l_bin
#
# exclusives:
# itemstatus = active | onhand | short | obsolete | orphaned
# joining filters:
# make model - makemodel
# serialnumber transdatefrom transdateto - invoice/orderitems
+# warehouse - warehouse
+# bin - bin
#
# binary flags:
# bought sold onorder ordered rfq quoted - aggreg joins with invoices/orders
# onhand - as above, but masking the simple itemstatus results (doh!)
# warehouse onhand
# search by overrides of description
+# soldtotal drops option default warehouse and bin
+# soldtotal can not work if there are no documents checked
#
# disabled sanity checks and changes:
# - searchitems = assembly will no longer disable bought
my ($self, $myconfig, $form) = @_;
my $dbh = $form->get_standard_dbh($myconfig);
+ # sanity backend check
+ croak "Cannot combine soldtotal with default bin or default warehouse" if ($form->{l_soldtotal} && ($form->{l_bin} || $form->{l_warehouse}));
+
$form->{parts} = +{ };
$form->{soldtotal} = undef if $form->{l_soldtotal}; # security fix. top100 insists on putting strings in there...
my @like_filters = (@simple_filters, @invoice_oi_filters);
my @all_columns = (@simple_filters, @makemodel_filters, @apoe_filters, @project_filters, qw(serialnumber));
my @simple_l_switches = (@all_columns, qw(notes listprice sellprice lastcost priceupdate weight unit rop image shop insertdate));
+ my %no_simple_l_switches = (warehouse => 'wh.description as warehouse', bin => 'bin.description as bin');
my @oe_flags = qw(bought sold onorder ordered rfq quoted);
my @qsooqr_flags = qw(invnumber ordnumber quonumber trans_id name module qty);
my @deliverydate_flags = qw(deliverydate);
) AS cv ON cv.id = apoe.customer_id OR cv.id = apoe.vendor_id|,
mv => 'LEFT JOIN vendor AS mv ON mv.id = mm.make',
project => 'LEFT JOIN project AS pj ON pj.id = COALESCE(ioi.project_id, apoe.globalproject_id)',
+ warehouse => 'LEFT JOIN warehouse AS wh ON wh.id = p.warehouse_id',
+ bin => 'LEFT JOIN bin ON bin.id = p.bin_id',
);
- my @join_order = qw(partsgroup makemodel mv invoice_oi apoe cv pfac project);
+ my @join_order = qw(partsgroup makemodel mv invoice_oi apoe cv pfac project warehouse bin);
my %table_prefix = (
deliverydate => 'apoe.', serialnumber => 'ioi.',
);
# if the join condition in these blocks are met, the column
- # of the scecified table will gently override (coalesce actually) the original value
+ # of the specified table will gently override (coalesce actually) the original value
# use it to conditionally coalesce values from subtables
my @column_override = (
# column name, prefix, joins_needed, nick name (in case column is named like another)
insertdate => 'itime::DATE',
);
- if ($form->{l_assembly} && $form->{l_lastcost}) {
- @simple_l_switches = grep { $_ ne 'lastcost' } @simple_l_switches;
- }
-
my $make_token_builder = sub {
my $joins_needed = shift;
sub {
# special case smart search
if ($form->{all}) {
- $form->{"l_$_"} = 1 for qw(partnumber description unit sellprice lastcost cvar_packaging linetotal);
+ $form->{"l_$_"} = 1 for qw(partnumber description unit sellprice lastcost linetotal);
+ $form->{l_service} = 1 if $form->{searchitems} eq 'service' || $form->{searchitems} eq '';
+ $form->{l_assembly} = 1 if $form->{searchitems} eq 'assembly' || $form->{searchitems} eq '';
+ $form->{l_part} = 1 if $form->{searchitems} eq 'part' || $form->{searchitems} eq '';
+ $form->{l_assortment} = 1 if $form->{searchitems} eq 'assortment' || $form->{searchitems} eq '';
push @where_tokens, "p.partnumber ILIKE ? OR p.description ILIKE ?";
push @bind_vars, (like($form->{all})) x 2;
}
push @select_tokens, $_;
}
- for ($form->{searchitems}) {
- push @where_tokens, "p.part_type = 'part'" if /part/;
- push @where_tokens, "p.part_type = 'service'" if /service/;
- push @where_tokens, "p.part_type = 'assembly'" if /assembly/;
- push @where_tokens, "p.part_type = 'assortment'" if /assortment/;
+ # Oder Bedingungen fuer Ware Dienstleistung Erzeugnis:
+ if ($form->{l_part} || $form->{l_assembly} || $form->{l_service} || $form->{l_assortment}) {
+ my @or_tokens = ();
+ push @or_tokens, "p.part_type = 'service'" if $form->{l_service};
+ push @or_tokens, "p.part_type = 'assembly'" if $form->{l_assembly};
+ push @or_tokens, "p.part_type = 'part'" if $form->{l_part};
+ push @or_tokens, "p.part_type = 'assortment'" if $form->{l_assortment};
+ push @where_tokens, join ' OR ', map { "($_)" } @or_tokens;
+ }
+ else {
+ # gar keine Teile
+ push @where_tokens, q|'F' = 'T'|;
}
+
if ( $form->{classification_id} > 0 ) {
push @where_tokens, "p.classification_id = ?";
push @bind_vars, $form->{classification_id};
FROM assembly a_lc
LEFT JOIN parts p_lc ON (a_lc.parts_id = p_lc.id)
LEFT JOIN price_factors pfac_lc ON (p_lc.price_factor_id = pfac_lc.id)
- WHERE (a_lc.id = p.id)) AS lastcost|;
+ WHERE (a_lc.id = p.id)) AS assembly_lastcost|;
$table_prefix{$q_assembly_lastcost} = ' ';
# special case makemodel search
$joins_needed{cv} = 1 if $bsooqr;
$joins_needed{apoe} = 1 if $joins_needed{project} || $joins_needed{cv} || grep { $form->{$_} || $form->{"l_$_"} } @apoe_filters;
$joins_needed{invoice_oi} = 1 if $joins_needed{project} || $joins_needed{apoe} || grep { $form->{$_} || $form->{"l_$_"} } @invoice_oi_filters;
+ $joins_needed{bin} = 1 if $form->{l_bin};
+ $joins_needed{warehouse} = 1 if $form->{l_warehouse};
# special case for description search.
# up in the simple filter section the description filter got interpreted as something like: WHERE description ILIKE '%$form->{description}%'
my $token_builder = $make_token_builder->(\%joins_needed);
- my @sort_cols = (@simple_filters, qw(id priceupdate onhand invnumber ordnumber quonumber name serialnumber soldtotal deliverydate insertdate shop));
+ my @sort_cols = (@simple_filters, qw(id onhand invnumber ordnumber quonumber name serialnumber soldtotal deliverydate insertdate shop));
$form->{sort} = 'id' unless grep { $form->{"l_$_"} } grep { $form->{sort} eq $_ } @sort_cols; # sort by id if unknown or invisible column
my $sort_order = ($form->{revers} ? ' DESC' : ' ASC');
my $order_clause = " ORDER BY " . $token_builder->($form->{sort}) . ($form->{revers} ? ' DESC' : ' ASC');
my $where_clause = join ' AND ', map { "($_)" } @where_tokens;
my $group_clause = @group_tokens ? ' GROUP BY ' . join ', ', map { $token_builder->($_) } @group_tokens : '';
+ # key of %no_simple_l_switch is the logical l_switch.
+ # the assigned value is the 'not so simple
+ # select token'
+ my $no_simple_select_clause;
+ foreach my $no_simple_l_switch (keys %no_simple_l_switches) {
+ next unless $form->{"l_${no_simple_l_switch}"};
+ $no_simple_select_clause .= ', '. $no_simple_l_switches{$no_simple_l_switch};
+ }
+ $select_clause .= $no_simple_select_clause;
+
my %oe_flag_to_cvar = (
bought => 'invoice',
sold => 'invoice',
push @bind_vars, @cvar_values;
}
+ # simple search for assemblies by items used in assemblies
+ if ($form->{bom} eq '2' && $form->{l_assembly}) {
+ # assembly_qty is the column name
+ $form->{l_assembly_qty} = 1;
+ # nuke where clause and bind vars
+ $where_clause = ' 1=1 AND p.id in (SELECT id from assembly where parts_id IN ' .
+ ' (select id from parts where 1=1';
+ @bind_vars = ();
+ # use only like filter for items used in assemblies
+ foreach (@like_filters) {
+ next unless $form->{$_};
+ $form->{"l_$_"} = '1'; # show the column
+ $where_clause .= " AND $_ ILIKE ? ";
+ push @bind_vars, like($form->{$_});
+ }
+ $where_clause .='))';
+ }
+
my $query = <<" SQL";
SELECT DISTINCT $select_clause
FROM parts p
$order_clause
$limit_clause
SQL
-
$form->{parts} = selectall_hashref_query($form, $dbh, $query, @bind_vars);
map { $_->{onhand} *= 1 } @{ $form->{parts} };
my @assemblies;
if ($form->{l_assembly} && $form->{bom}) {
$query =
- qq|SELECT p.id, p.partnumber, p.description, a.qty AS onhand,
+ qq|SELECT p.id, p.partnumber, p.description, a.qty AS assembly_qty,
p.unit, p.notes, p.itime::DATE as insertdate,
p.sellprice, p.listprice, p.lastcost,
- p.rop, p.weight, p.priceupdate,
+ p.rop, p.weight,
p.image, p.drawing, p.microfiche,
pfac.factor
FROM parts p
$main::lxdebug->leave_sub();
- return @{ $form->{parts} };
-}
-
-sub _create_filter_for_priceupdate {
- $main::lxdebug->enter_sub();
-
- my $self = shift;
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
-
- my @where_values;
- my $where = '1 = 1';
-
- foreach my $item (qw(partnumber drawing microfiche make model pg.partsgroup)) {
- my $column = $item;
- $column =~ s/.*\.//;
- next unless ($form->{$column});
-
- $where .= qq| AND $item ILIKE ?|;
- push(@where_values, like($form->{$column}));
- }
-
- foreach my $item (qw(description serialnumber)) {
- next unless ($form->{$item});
-
- $where .= qq| AND (${item} ILIKE ?)|;
- push(@where_values, like($form->{$item}));
- }
-
-
- # items which were never bought, sold or on an order
- if ($form->{itemstatus} eq 'orphaned') {
- $where .=
- qq| AND (p.onhand = 0)
- AND p.id NOT IN
- (
- SELECT DISTINCT parts_id FROM invoice
- UNION
- SELECT DISTINCT parts_id FROM assembly
- UNION
- SELECT DISTINCT parts_id FROM orderitems
- )|;
-
- } elsif ($form->{itemstatus} eq 'active') {
- $where .= qq| AND p.obsolete = '0'|;
-
- } elsif ($form->{itemstatus} eq 'obsolete') {
- $where .= qq| AND p.obsolete = '1'|;
-
- } elsif ($form->{itemstatus} eq 'onhand') {
- $where .= qq| AND p.onhand > 0|;
-
- } elsif ($form->{itemstatus} eq 'short') {
- $where .= qq| AND p.onhand < p.rop|;
-
- }
-
- foreach my $column (qw(make model)) {
- next unless ($form->{$column});
- $where .= qq| AND p.id IN (SELECT DISTINCT parts_id FROM makemodel WHERE $column ILIKE ?|;
- push(@where_values, like($form->{$column}));
- }
-
- $main::lxdebug->leave_sub();
-
- return ($where, @where_values);
-}
-
-sub get_num_matches_for_priceupdate {
- $main::lxdebug->enter_sub();
-
- my $self = shift;
-
- my $myconfig = \%main::myconfig;
- my $form = $main::form;
-
- my $dbh = $form->get_standard_dbh($myconfig);
-
- my ($where, @where_values) = $self->_create_filter_for_priceupdate();
-
- my $num_updated = 0;
- my $query;
-
- for my $column (qw(sellprice listprice)) {
- next if ($form->{$column} eq "");
-
- $query =
- qq|SELECT COUNT(*)
- FROM parts
- WHERE id IN
- (SELECT p.id
- FROM parts p
- LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
- WHERE $where)|;
- my ($result) = selectfirst_array_query($form, $dbh, $query, @where_values);
- $num_updated += $result if (0 <= $result);
- }
-
- $query =
- qq|SELECT COUNT(*)
- FROM prices
- WHERE parts_id IN
- (SELECT p.id
- FROM parts p
- LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
- WHERE $where) AND (pricegroup_id = ?)|;
- my $sth = prepare_query($form, $dbh, $query);
-
- for my $i (1 .. $form->{price_rows}) {
- next if ($form->{"price_$i"} eq "");
-
- my ($result) = do_statement($form, $sth, $query, @where_values, conv_i($form->{"pricegroup_id_$i"}));
- $num_updated += $result if (0 <= $result);
- }
- $sth->finish();
-
- $main::lxdebug->leave_sub();
-
- return $num_updated;
-}
-
-sub update_prices {
- my ($self, $myconfig, $form) = @_;
- $main::lxdebug->enter_sub();
-
- my $num_updated = SL::DB->client->with_transaction(\&_update_prices, $self, $myconfig, $form);
-
- $main::lxdebug->leave_sub();
- return $num_updated;
-}
-
-sub _update_prices {
- my ($self, $myconfig, $form) = @_;
-
- my ($where, @where_values) = $self->_create_filter_for_priceupdate();
- my $num_updated = 0;
-
- # connect to database
- my $dbh = SL::DB->client->dbh;
-
- for my $column (qw(sellprice listprice)) {
- next if ($form->{$column} eq "");
-
- my $value = $form->parse_amount($myconfig, $form->{$column});
- my $operator = '+';
-
- if ($form->{"${column}_type"} eq "percent") {
- $value = ($value / 100) + 1;
- $operator = '*';
- }
-
- my $query =
- qq|UPDATE parts SET $column = $column $operator ?
- WHERE id IN
- (SELECT p.id
- FROM parts p
- LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
- WHERE $where)|;
- my $result = do_query($form, $dbh, $query, $value, @where_values);
- $num_updated += $result if (0 <= $result);
- }
-
- my $q_add =
- qq|UPDATE prices SET price = price + ?
- WHERE parts_id IN
- (SELECT p.id
- FROM parts p
- LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
- WHERE $where) AND (pricegroup_id = ?)|;
- my $sth_add = prepare_query($form, $dbh, $q_add);
-
- my $q_multiply =
- qq|UPDATE prices SET price = price * ?
- WHERE parts_id IN
- (SELECT p.id
- FROM parts p
- LEFT JOIN partsgroup pg ON (p.partsgroup_id = pg.id)
- WHERE $where) AND (pricegroup_id = ?)|;
- my $sth_multiply = prepare_query($form, $dbh, $q_multiply);
-
- for my $i (1 .. $form->{price_rows}) {
- next if ($form->{"price_$i"} eq "");
-
- my $value = $form->parse_amount($myconfig, $form->{"price_$i"});
- my $result;
-
- if ($form->{"pricegroup_type_$i"} eq "percent") {
- $result = do_statement($form, $sth_multiply, $q_multiply, ($value / 100) + 1, @where_values, conv_i($form->{"pricegroup_id_$i"}));
- } else {
- $result = do_statement($form, $sth_add, $q_add, $value, @where_values, conv_i($form->{"pricegroup_id_$i"}));
- }
-
- $num_updated += $result if (0 <= $result);
- }
-
- $sth_add->finish();
- $sth_multiply->finish();
-
- return $num_updated;
+ return $form->{parts};
}
# get partnumber, description, unit, sellprice and soldtotal with choice through $sortorder for Top100
}
$j++;
- $form->{"type_and_classific_$j"} = $::request->presenter->type_abbreviation($ref->{part_type}).
- $::request->presenter->classification_abbreviation($ref->{classification_id});
+ $form->{"type_and_classific_$j"} = type_abbreviation($ref->{part_type}).
+ classification_abbreviation($ref->{classification_id});
$form->{"id_$j"} = $ref->{id};
$form->{"partnumber_$j"} = $ref->{partnumber};
$form->{"description_$j"} = $ref->{description};
# transdate madness.
my $transdate = "";
- if ($form->{type} eq "invoice" or $form->{type} eq "credit_note") {
+ if (($form->{type} eq "invoice") or ($form->{type} eq "credit_note") or ($form->{script} eq 'ir.pl')) {
# use deliverydate for sales and purchase invoice, if it exists
# also use deliverydate for credit notes
- if (!$form->{deliverydate}) {
- $transdate = $form->{invdate};
- } else {
- $transdate = $form->{deliverydate};
- }
- } elsif ($form->{script} eq 'ir.pl') {
- # when a purchase invoice is opened from the report of purchase invoices
- # $form->{type} isn't set, but $form->{script} is, not sure why this is or
- # whether this distinction matters in some other scenario. Otherwise one
- # could probably take out this elsif and add a
- # " or $form->{script} eq 'ir.pl' "
- # to the above if-statement
- if (!$form->{deliverydate}) {
- $transdate = $form->{invdate};
- } else {
- $transdate = $form->{deliverydate};
- }
- } elsif (($form->{type} eq "credit_note") and $form->{deliverydate}) {
- # if credit_note has a deliverydate, use this instead of invdate
- # useful for credit_notes of invoices from an old period with different tax
- # if there is no deliverydate then invdate is used, old default (see next elsif)
- # Falls hier der Stichtag für Steuern anders bestimmt wird,
- # entsprechend auch bei Taxkeys.pm anpassen
- $transdate = $form->{deliverydate};
- } elsif (($form->{type} eq "credit_note") || ($form->{script} eq 'ir.pl')) {
- $transdate = $form->{invdate};
+ $transdate = $form->{tax_point} || $form->{deliverydate} || $form->{invdate};
} else {
- $transdate = $form->{transdate};
+ my $deliverydate;
+ $deliverydate = $form->{reqdate} if any { $_ eq $form->{type} } qw(sales_order request_quotation purchase_order);
+ $transdate = $form->{tax_point} || $deliverydate || $form->{transdate};
}
if ($transdate eq "") {
p.id IN ($in)
SQL
- my $sth_tax = prepare_query($::form, $dbh, <<SQL);
- SELECT c.accno, t.taxdescription AS description, t.rate, t.taxnumber
+ my $query_tax = <<SQL;
+ SELECT c.accno, t.taxdescription AS description, t.id as tax_id, t.rate,
+ c.accno as taxnumber
FROM tax t
LEFT JOIN chart c ON c.id = t.chart_id
WHERE t.id IN
WHERE tk.chart_id = ? AND startdate <= ?
ORDER BY startdate DESC LIMIT 1)
SQL
+ my $sth_tax = prepare_query($::form, $dbh, $query_tax);
while (my ($index => $part_id) = each %args) {
my $ref = $accno_by_part{$part_id} or next;
$form->{"${_}_accno_$index"} = $accounts{"${_}_accno"} for qw(inventory income expense);
- $sth_tax->execute($accounts{$inc_exp}, quote_db_date($transdate));
+ $sth_tax->execute($accounts{$inc_exp}, quote_db_date($transdate)) || $::form->dberror($query_tax);
$ref = $sth_tax->fetchrow_hashref or next;
$form->{"taxaccounts_$index"} = $ref->{"accno"};
$form->{"taxaccounts"} .= "$ref->{accno} "if $form->{"taxaccounts"} !~ /$ref->{accno}/;
- $form->{"$ref->{accno}_${_}"} = $ref->{$_} for qw(rate description taxnumber);
+ $form->{"$ref->{accno}_${_}"} = $ref->{$_} for qw(rate description taxnumber tax_id);
}
$sth_tax->finish;
$sth->finish();
+ $query = qq|SELECT
+ cp.parts_id,
+ cp.customer_partnumber AS customer_model,
+ c.name AS customer_make
+ FROM part_customer_prices cp
+ LEFT JOIN customer c ON (cp.customer_id = c.id)
+ WHERE cp.parts_id IN ($placeholders)|;
+
+ my %customermodel = ();
+
+ $sth = prepare_execute_query($form, $dbh, $query, @part_ids);
+
+ while (my $ref = $sth->fetchrow_hashref()) {
+ $customermodel{$ref->{parts_id}} ||= [];
+ push @{ $customermodel{$ref->{parts_id}} }, $ref;
+ }
+
+ $sth->finish();
+
my @columns = qw(ean image microfiche drawing);
$query = qq|SELECT id, | . join(', ', @columns) . qq|
my %data = selectall_as_map($form, $dbh, $query, 'id', \@columns, @part_ids);
my %template_arrays;
- map { $template_arrays{$_} = [] } (qw(make model), @columns);
+ map { $template_arrays{$_} = [] } (qw(make model customer_make customer_model), @columns);
foreach my $i (1 .. $rowcount) {
my $id = $form->{"${prefix}${i}"};
push @{ $template_arrays{make} }, [];
push @{ $template_arrays{model} }, [];
- next if (!$makemodel{$id});
+ if ($makemodel{$id}) {
+ foreach my $ref (@{ $makemodel{$id} }) {
+ map { push @{ $template_arrays{$_}->[-1] }, $ref->{$_} } qw(make model);
+ }
+ }
+
+ push @{ $template_arrays{customer_make} }, [];
+ push @{ $template_arrays{customer_model} }, [];
- foreach my $ref (@{ $makemodel{$id} }) {
- map { push @{ $template_arrays{$_}->[-1] }, $ref->{$_} } qw(make model);
+ if ($customermodel{$id}) {
+ foreach my $ref (@{ $customermodel{$id} }) {
+ push @{ $template_arrays{$_}->[-1] }, $ref->{$_} for qw(customer_make customer_model);
+ }
}
+
}
my $parts = SL::DB::Manager::Part->get_all(query => [ id => \@part_ids ]);
my $id = $form->{"${prefix}${i}"};
next unless $id;
my $prt = $parts_by_id{$id};
- my $type_abbr = $::request->presenter->type_abbreviation($prt->part_type);
- push @{ $template_arrays{part_type} }, $type_abbr;
- push @{ $template_arrays{type_and_classific}}, $type_abbr.$::request->presenter->classification_abbreviation($prt->classification_id);
- push @{ $template_arrays{separate} }, $::request->presenter->separate_abbreviation($prt->classification_id);
+ my $type_abbr = type_abbreviation($prt->part_type);
+ push @{ $template_arrays{part_type} }, $prt->part_type;
+ push @{ $template_arrays{part_abbreviation} }, $type_abbr;
+ push @{ $template_arrays{type_and_classific}}, $type_abbr . classification_abbreviation($prt->classification_id);
+ push @{ $template_arrays{separate} }, separate_abbreviation($prt->classification_id);
}
$main::lxdebug->leave_sub();
return %template_arrays;
}
-sub normalize_text_blocks {
- $main::lxdebug->enter_sub();
-
- my $self = shift;
- my %params = @_;
-
- my $form = $params{form} || $main::form;
-
- # check if feature is enabled (select normalize_part_descriptions from defaults)
- return unless ($::instance_conf->get_normalize_part_descriptions);
-
- foreach (qw(description notes)) {
- $form->{$_} =~ s/\s+$//s;
- $form->{$_} =~ s/^\s+//s;
- $form->{$_} =~ s/ {2,}/ /g;
- }
- $main::lxdebug->leave_sub();
-}
-
-
1;