<& elements/edit.html, 'post_url' => popurl(1).'process/part_pkg.cgi', 'name' => "Package definition", 'table' => 'part_pkg', 'agent_virt' => 1, 'agent_null_right' => $edit_global, 'agent_clone_extra_sql' => $agent_clone_extra_sql, #'viewall_dir' => 'browse', 'viewall_url' => $p.'browse/part_pkg.cgi', 'html_init' => include('/elements/init_overlib.html'). include('/elements/init_calendar.html'). $javascript, 'html_bottom' => $html_bottom, 'extra_fields_validate' => $validate_priceplan_fields, 'body_etc' => 'onLoad="agent_changed(document.edit_topform.agentnum); aux_planchanged(document.edit_topform.plan); hide_supp_pkgs()"', 'begin_callback' => $begin_callback, 'end_callback' => $end_callback, 'new_hashref_callback' => $new_hashref_callback, 'new_object_callback' => $new_object_callback, 'new_callback' => $new_callback, 'clone_callback' => $clone_callback, 'edit_callback' => $edit_callback, 'error_callback' => $error_callback, 'field_callback' => $field_callback, 'onsubmit' => 'confirm_submit', 'labels' => { 'pkgpart' => 'Package Definition', 'pkg' => 'Package', %locale_field_labels, 'comment' => 'Comment (customer-hidden)', 'classnum' => 'Package class', 'addon_classnum' => 'Restrict additional orders to package class', 'promo_code' => 'Promotional code', 'freq' => 'Recurring fee frequency', 'setuptax' => 'Setup fee tax exempt', 'recurtax' => 'Recurring fee tax exempt', 'taxclass' => 'Tax class', 'plan' => 'Price plan', 'disabled' => 'Disable new orders', 'disable_line_item_date_ranges' => 'Disable line item date ranges', 'start_on_hold' => 'Start on hold', 'setup_cost' => 'Setup cost', 'recur_cost' => 'Recur cost', 'pay_weight' => 'Payment weight', 'credit_weight' => 'Credit weight', 'agent_pkgpartid' => 'External ID', 'agentnum' => 'Agent', 'agent_type' => ' ', #just its title headingn is fine 'setup_fee' => 'Setup fee', 'setup_show_zero' => 'Show zero setup', 'recur_fee' => 'Recurring fee', 'recur_show_zero' => 'Show zero recurring', ( map { ( "setup_fee_$_" => "Setup fee $_", "recur_fee_$_" => "Recurring fee $_", ); } $conf->config('currencies') ), 'usagepricepart' => ' ', 'discountnum' => 'Offer discounts for longer terms', 'bill_dst_pkgpart' => 'Include line item(s) from package', 'svc_dst_pkgpart' => 'Include services of package', 'supp_dst_pkgpart' => 'When ordering package, also order', 'report_option' => 'Report classes', 'delay_start' => 'Default delay (days)', 'adjourn_months' => 'Suspend the package after ', 'contract_end_months' => 'Contract ends after ', 'expire_months' => 'Cancel the package after ', 'change_to_pkgpart'=> 'and replace it with ', 'units_taxproductnum' => 'Per-line tax product', }, 'fields' => [ { field=>'clone', type=>'hidden', curr_value_callback => sub { shift->param('clone') }, }, { field=>'pkgnum', type=>'hidden', curr_value_callback => sub { shift->param('pkgnum') }, }, { field=>'custom', type=>'hidden' }, { field=>'family_pkgpart', type=>'hidden' }, { field=>'successor', type=>'hidden' }, { type => 'columnstart' }, { field => 'pkg', type => 'input-locale-text', size => 40, #32 maxlength => 50, }, #@locale_fields, {field=>'comment', type=>'text', size=>40 }, #32 { field => 'agentnum', type => 'select-agent', disable_empty => ! $acl_edit_global, empty_label => '(global)', onchange => 'agent_changed', }, {field=>'classnum', type=>'select-pkg_class' }, ( $conf->exists('pkg-addon_classnum') ? ( { field=>'addon_classnum', type =>'select-pkg_class', } ) : () ), {field=>'disabled', type=>$disabled_type, value=>'Y'}, {field=>'disable_line_item_date_ranges', type=>$disabled_type, value=>'Y'}, { field => 'start_on_hold', type => 'checkbox', value => 'Y' }, { type => 'tablebreak-tr-title', value => 'Pricing', #better name? }, { field => 'plan', type => 'selectlayers-select', options => [ keys %plan_labels ], labels => \%plan_labels, onchange => 'aux_planchanged(what);', }, { field => 'setup_fee', type => 'money', onchange => 'setup_changed', }, { field => 'setup_show_zero', type => 'checkbox', value => 'Y', disabled => sub { $setup_show_zero_disabled }, }, ( map { +{ field => "setup_fee_$_", type => 'text', prefix=> currency_symbol($_, SYM_HTML), size => 8, } } sort $conf->config('currencies') ), { field => 'freq', type => 'part_pkg_freq', onchange => 'freq_changed', }, { field => 'recur_fee', type => 'money', disabled => sub { $recur_disabled }, onchange => 'recur_changed', }, { field => 'recur_show_zero', type => 'checkbox', value => 'Y', disabled => sub { $recur_show_zero_disabled }, }, ( map { +{ field => "recur_fee_$_", type => 'text', prefix=> currency_symbol($_, SYM_HTML), size => 8, } } sort $conf->config('currencies') ), ( $conf->exists('part_pkg-delay_start') ? ( { type => 'tablebreak-tr-title', value => 'Delayed start', }, { field => 'delay_start', type => 'text', size => 6 }, ) : () ), { type => 'tablebreak-tr-title', value => 'Limited duration', }, { field => 'adjourn_months', type => 'select-months', }, { field => 'contract_end_months', type => 'select-months', }, { field => 'expire_months', type => 'select-expire_months', }, { field => 'change_to_pkgpart', type => 'select-part_pkg', extra_sql => sub { $pkgpart ? "AND part_pkg.pkgpart != $pkgpart" : '' }, empty_label => 'no package', }, #price plan #setup fee #recurring frequency #recurring fee (auto-disable) { type => 'columnnext' }, {type=>'justtitle', value=>'Taxation' }, {field=>'setuptax', type=>'checkbox', value=>'Y'}, {field=>'recurtax', type=>'checkbox', value=>'Y'}, {field=>'taxclass', type=>'select-taxclass' }, { field => 'taxproductnums', type => 'hidden', value => join(',', @taxproductnums), }, { field => 'taxproductnum', type => 'part_pkg-taxproducts', include_opt_callback => sub { pkgpart => $_[0]->pkgpart }, }, { field => 'units_taxproductnum', type => ($tax_data_vendor ? 'select-taxproduct' : 'hidden'), }, { type => 'tablebreak-tr-title', value => 'Promotions', #better name? }, { field=>'promo_code', type=>'text', size=>15 }, { type => 'tablebreak-tr-title', value => 'Cost tracking', #better name? }, ( $curuser->access_right('Edit package definition costs') ? ( { field=>'setup_cost', type=>'money', }, { field=>'recur_cost', type=>'money', }, ) : ( { field=>'setup_cost', type=>'fixed', }, { field=>'recur_cost', type=>'fixed', }, ) ), { type => 'columnnext' }, {type=>'justtitle', value=>'Agent (reseller) types' }, { field => 'agent_type', type => 'select-agent_type', disabled => ! $acl_edit_global, element_etc => 'size="10"', multiple => '1', #cause edit.html is dum curr_value_callback => sub { my($cgi, $object, $field) = @_; #in the other callbacks..? hmm. \@agent_type; }, }, ($fcc_opts ? ( { type => 'tablebreak-tr-title', value => 'FCC Form 477 information', }, { field => 'fcc_options_string', type => 'input-fcc_options', curr_value_callback => sub { my ($cgi, $part_pkg, $fref) = @_; if ( $cgi->param('fcc_options_string') ) { # error redirect return $cgi->param('fcc_options_string'); } my %hash; %hash = $part_pkg->fcc_options if ($part_pkg->pkgpart); return encode_json(\%hash); }, }, ) : () ), { type => 'tablebreak-tr-title', value => 'External Links', #better name? }, { field=>'agent_pkgpartid', type=>'text', size=>21 }, { type => 'tablebreak-tr-title', value => 'Line-item revenue recognition', #better name? }, { field=>'pay_weight', type=>'text', size=>6 }, { field=>'credit_weight', type=>'text', size=>6 }, { type => 'columnend' }, { type => 'tablebreak-tr-title', value => 'Usage pricing add-ons', #better name? just 'Usage pricing' ? there's also CDR usage pricing, RADIUS usage pricing, etc :/ }, { 'field' => 'usagepricepart', 'type' => 'part_pkg_usageprice', 'o2m_table' => 'part_pkg_usageprice', 'm2_label' => ' ', 'm2_error_callback' => $usageprice_error_callback, }, { 'type' => $report_option ? 'tablebreak-tr-title' : 'hidden', 'value' => 'Optional report classes', 'field' => 'census_title', }, { 'field' => 'report_option', 'type' => $report_option ? 'select-table' : 'hidden', 'table' => 'part_pkg_report_option', 'name_col' => 'name', 'hashref' => { 'disabled' => '' }, 'multiple' => 1, 'curr_value_callback' => $report_option_value_callback, }, { 'type' => 'tablebreak-tr-title', 'value' => 'Term discounts', }, { 'field' => 'discountnum', 'type' => 'select-table', 'table' => 'discount', 'name_col' => 'name', 'hashref' => { %$discountnum_hashref }, #'extra_sql' => 'AND (months IS NOT NULL OR months != 0)', 'empty_label'=> 'Select discount', 'm2_label' => 'Offer discounts for longer terms', 'm2m_method' => 'part_pkg_discount', 'm2m_dstcol' => 'discountnum', 'm2_error_callback' => $discount_error_callback, }, { 'type' => 'tablebreak-tr-title', 'value' => 'Pricing add-ons', 'colspan' => 4, }, { 'field' => 'bill_dst_pkgpart', 'type' => 'select-part_pkg', 'extra_sql' => sub { $pkgpart ? "AND part_pkg.pkgpart != $pkgpart" : '' }, 'label_callback' => sub { shift->pkg_comment_only }, 'm2_label' => 'Include line item(s) from package', 'm2m_method' => 'bill_part_pkg_link', 'm2m_dstcol' => 'dst_pkgpart', 'm2_error_callback' => &{$m2_error_callback_maker}('bill'), 'm2_fields' => [ { 'field' => 'hidden', 'type' => 'checkbox', 'value' => 'Y', 'curr_value' => '', 'label' => 'Bundle', }, ], }, { type => 'tablebreak-tr-title', value => 'Services', }, { type => 'pkg_svc', }, { 'field' => 'svc_dst_pkgpart', 'label' => 'Also include services from package: ', 'type' => 'select-part_pkg', 'extra_sql' => sub { $pkgpart ? "AND part_pkg.pkgpart != $pkgpart" : '' }, 'label_callback' => sub { shift->pkg_comment_only }, 'm2_label' => 'Include services of package: ', 'm2m_method' => 'svc_part_pkg_link', 'm2m_dstcol' => 'dst_pkgpart', 'm2_error_callback' => &{$m2_error_callback_maker}('svc'), }, { 'type' => 'tablebreak-tr-title', 'value' => 'Supplemental packages', 'colspan' => '4', 'include_opt_callback' => sub { 'id' => 'show_supp_pkgs', }, }, { 'field' => 'supp_dst_pkgpart', 'type' => 'select-part_pkg', 'label_callback' => sub { shift->pkg_comment_only }, 'm2_label' => 'When ordering package, also order', 'm2m_method' => 'supp_part_pkg_link', 'm2m_dstcol' => 'dst_pkgpart', 'm2_error_callback' => &{$m2_error_callback_maker}('supp'), }, { type => 'tablebreak-tr-title', value => 'Price plan options', }, ], &> <%init> my $curuser = $FS::CurrentUser::CurrentUser; my $edit_global = 'Edit global package definitions'; my $acl_edit = $curuser->access_right('Edit package definitions'); my $acl_edit_global = $curuser->access_right($edit_global); my $acl_edit_either = $acl_edit || $acl_edit_global; my $begin_callback = sub { my( $cgi, $fields, $opt ) = @_; die "access denied" unless $acl_edit_either || ( $cgi->param('pkgnum') && $curuser->access_right('Customize customer package') ); }; my $disabled_type = $acl_edit_either ? 'checkbox' : 'hidden'; #arg. access rights for cloning are Hard. # on the one hand we don't really want cloning (customizing a package) to fail # for want of finding the source package in normal usage # on the other hand, we don't want people using the clone link to be able to # see my $agent_clone_extra_sql = ' ( '. FS::part_pkg->curuser_pkgs_sql. " OR ( part_pkg.custom = 'Y' ) ". ' ) '; my $conf = new FS::Conf; my $tax_data_vendor = $conf->config('tax_data_vendor'); my $fcc_opts = $conf->exists('part_pkg-show_fcc_options'); my @locales = grep { ! /^en_/i } $conf->config('available-locales'); #should filter from the default locale lang instead of en_ my %locale_labels = map { ( $_ => 'Package -- '. FS::Locales->description($_) ) } @locales; @locales = sort { $locale_labels{$a} cmp $locale_labels{$b} } @locales; my $n = 0; my %locale_field_labels = ( map { ( 'pkgpartmsgnum'. $n++. '_pkg' => $locale_labels{$_} ); } @locales ); my $sth = dbh->prepare("SELECT COUNT(*) FROM part_pkg_report_option". " WHERE disabled IS NULL OR disabled = '' ") or die dbh->errstr; $sth->execute or die $sth->errstr; my $report_option = $sth->fetchrow_arrayref->[0]; #XXX # - tr-part_pkg_freq: month_increments_only (from price plans) # - test cloning # - test errors cloning # - test custom pricing # - move the selectlayer divs away from lame layer_callback #my ($query) = $cgi->keywords; # #my $part_pkg = ''; my @agent_type = (); my %tax_override = (); my %taxproductnums = map { ($_->classnum => 1) } qsearch('usage_class', { 'disabled' => '' }); my @taxproductnums = ( qw( setup recur ), sort (keys %taxproductnums) ); my %options = (); my $recur_disabled = 1; my $setup_show_zero_disabled = 0; my $recur_show_zero_disabled = 1; my $pkgpart = ''; my $error_callback = sub { my($cgi, $object, $fields, $opt ) = @_; (@agent_type) = $cgi->param('agent_type'); $opt->{action} = 'Custom' if $cgi->param('pkgnum'); $setup_show_zero_disabled = ($cgi->param('setup_fee') > 0) ? 1 : 0; $recur_disabled = $cgi->param('freq') ? 0 : 1; $recur_show_zero_disabled = $cgi->param('freq') ? $cgi->param('recur_fee') > 0 ? 1 : 0 : 1; foreach ($cgi->param) { /^usage_taxproductnum_(\d+)$/ && ($taxproductnums{$1} = 1); } $tax_override{''} = $cgi->param('tax_override'); $tax_override{$_} = $cgi->param('tax_override_$_') foreach(grep { /^tax_override_(\w+)$/ } $cgi->param); #some false laziness w/process $cgi->param('plan') =~ /^(\w+)$/ or die 'unparsable plan'; my $plan = $1; my $options = $cgi->param($plan."__OPTIONS"); my @options = split(',', $options); %options = map { my $optionname = $_; my $param = $plan."__$optionname"; my $value = join(', ', $cgi->param($param)); ( $optionname => $value ); } @options; $object->set($_ => scalar($cgi->param($_)) ) foreach (qw( setup_fee recur_fee disable_line_item_date_ranges )); foreach my $currency ( $conf->config('currencies') ) { my %part_pkg_currency = $object->part_pkg_currency_options($currency); foreach (qw( setup_fee recur_fee )) { my $param = $_.'_'.$currency; $object->set( $param, $cgi->param($param) ); } } $pkgpart = $object->pkgpart; if ( $cgi->param('error') =~ / is suggested with / ) { #yeah, detection is a shitty kludge, but we don't have exception objects $opt->{form_init} = ' Override suggestion

'; } }; my $new_hashref_callback = sub { { 'plan' => 'flat' }; }; my $new_object_callback = sub { my( $cgi, $hashref, $fields, $opt ) = @_; my $part_pkg = FS::part_pkg->new( $hashref ); $part_pkg->set($_ => '0') foreach (qw( setup_fee recur_fee disable_line_item_date_ranges )); $part_pkg; }; my $report_option_value_callback = sub { my ($cgi, $object) = @_; my @report_option; if ( defined $cgi->param('report_option') ) { @report_option = $cgi->param('report_option'); } else { foreach ($object->options) { /^report_option_(\d+)$/ && (push @report_option, $1); } } join(',', @report_option); }; sub set_report_option { my($cgi, $object, $fields ) = @_; #, $opt my @report_option = (); foreach ($object->options) { /^usage_taxproductnum_(\d+)$/ && ($taxproductnums{$1} = 1); # /^report_option_(\d+)$/ && (push @report_option, $1); } foreach ($object->part_pkg_taxoverride) { $taxproductnums{$_->usage_class} = 1 if $_->usage_class; } # $cgi->param('report_option', join(',', @report_option)); # foreach my $field ( @$fields ) { # next unless ( # ref($field) eq 'HASH' && # $field->{field} && # $field->{field} eq 'report_option' # ); # #$field->{curr_value} = join(',', @report_option); # $field->{value} = join(',', @report_option); # } } my $edit_callback = sub { my( $cgi, $object, $fields, $opt ) = @_; $setup_show_zero_disabled = ($object->option('setup_fee') > 0) ? 1 : 0; $recur_disabled = $object->freq ? 0 : 1; $recur_show_zero_disabled = $object->freq ? $object->option('recur_fee') > 0 ? 1 : 0 : 1; (@agent_type) = map {$_->typenum} qsearch('type_pkgs', { 'pkgpart' => $object->pkgpart } ); set_report_option( $cgi, $object, $fields); %options = $object->options; $object->set($_ => $object->option($_, 1)) foreach (qw( setup_fee recur_fee disable_line_item_date_ranges )); foreach my $currency ( $conf->config('currencies') ) { my %part_pkg_currency = $object->part_pkg_currency_options($currency); $object->set( $_.'_'.$currency, $part_pkg_currency{$_} ) foreach keys %part_pkg_currency; } $pkgpart = $object->pkgpart; }; my $new_callback = sub { my( $cgi, $object, $fields ) = @_; my $conf = new FS::Conf; if ( $conf->exists('agent_defaultpkg') ) { @agent_type = map {$_->typenum} qsearch('agent_type', { 'disabled'=>'' }); } $options{'suspend_bill'}=1 if $conf->exists('part_pkg-default_suspend_bill'); }; my $clone_callback = sub { my( $cgi, $object, $fields, $opt ) = @_; if ( $cgi->param('pkgnum') ) { my $cust_pkg = qsearchs('cust_pkg', { 'pkgnum' => scalar($cgi->param('pkgnum')) } ); $object->agentnum( $cust_pkg->cust_main->agentnum ); $opt->{action} = 'Custom'; #my $part_pkg = $clone_part_pkg->clone; #this is all clone does anyway $object->custom('Y'); $object->disabled('Y'); } else { #when explicitly cloning, not customizing (@agent_type) = map {$_->typenum} qsearch('type_pkgs',{ 'pkgpart' => $object->pkgpart } ); } set_report_option( $cgi, $object, $fields); %options = $object->options; $object->set($_ => $options{$_}) foreach (qw( setup_fee recur_fee disable_line_item_date_ranges )); $recur_disabled = $object->freq ? 0 : 1; $recur_show_zero_disabled = $object->freq ? $object->option('recur_fee') > 0 ? 1 : 0 : 1; foreach my $currency ( $conf->config('currencies') ) { my %part_pkg_currency = $object->part_pkg_currency_options($currency); $object->set( $_.'_'.$currency, $part_pkg_currency{$_} ) foreach keys %part_pkg_currency; } }; my $discount_error_callback = sub { my( $cgi, $object ) = @_; map { if ( /^discountnum(\d+)$/ && ( my $discountnum = $cgi->param("discountnum$1") ) ) { new FS::part_pkg_discount { 'pkgpart' => $object->pkgpart, 'discountnum' => $discountnum, }; } else { (); } } $cgi->param; }; my $usageprice_error_callback = sub { my( $cgi, $object ) = @_; map { if ( /^usagepricepart(\d+)_price$/ && $cgi->param("usagepricepart$1_price") ) { new FS::part_pkg_usageprice { 'usagepricepart' => scalar($cgi->param("usagepricepart$1")), 'pkgpart' => $object->pkgpart, 'price' => scalar($cgi->param("usagepricepart$1_price")), #'currency 'action' => scalar($cgi->param("usagepricepart$1_action")), 'target' => scalar($cgi->param("usagepricepart$1_target")), 'amount' => scalar($cgi->param("usagepricepart$1_amount")), }; } else { (); } } $cgi->param; }; my $m2_error_callback_maker = sub { my $link_type = shift; #yay closures return sub { my( $cgi, $object ) = @_; map { if ( /^${link_type}_dst_pkgpart(\d+)$/ && ( my $dst = $cgi->param("${link_type}_dst_pkgpart$1") ) ) { my $hidden = $cgi->param("${link_type}_dst_pkgpart__hidden$1") || ''; new FS::part_pkg_link { 'link_type' => $link_type, 'src_pkgpart' => $object->pkgpart, 'dst_pkgpart' => $dst, 'hidden' => $hidden, }; } else { (); } } $cgi->param; }; }; my $javascript = <<'END'; "; tie my %plans, 'Tie::IxHash', %{ FS::part_pkg::plan_info() }; tie my %plan_labels, 'Tie::IxHash', map { $_ => ( $plans{$_}->{'shortname'} || $plans{$_}->{'name'} ) } keys %plans; my $validate_priceplan_fields = {}; foreach my $priceplan (keys %plans) { my $plan_fields = $plans{$priceplan}->{fields}; foreach my $price_plan_field (keys %$plan_fields) { $validate_priceplan_fields->{$priceplan."__".$price_plan_field} = $plan_fields->{$price_plan_field}->{"js_validate"} if exists $plan_fields->{$price_plan_field}->{"js_validate"}; } } my $html_bottom = sub { my( $object ) = @_; #warn join("\n", map { "$_: $options{$_}" } keys %options ). "\n"; my $layer_callback = sub { my $layer = shift; my $html = ntable("#cccccc",2); #$html .= ' # # Recurring fee frequency # '; my $href = $plans{$layer}->{'fields'}; my @fields; if ( $plans{$layer}->{'fieldorder'} ) { @fields = @{ $plans{$layer}->{'fieldorder'} }; } else { warn "FS::part_pkg::$layer has no fieldorder.\n"; @fields = keys %$href; } # hash of dependencies for each of the Pricing Plan fields. # make sure NOT to use double-quotes inside the 'msg' value. my $dependencies = { 'unused_credit_suspend' => { 'msg' => q|You must set the 'suspend_credit_type' option in Configuration->Settings to gain access to this option.|, 'are_met' => sub{ my $conf = new FS::conf; my @conf_info = qsearch('conf', { 'name' => 'suspend_credit_type' } ); return 1 if (exists($conf_info[0]) && $conf_info[0]->{Hash}{value}); return 0; } }, 'unused_credit_cancel' => { 'msg' => q|You must set the 'cancel_credit_type' option in Configuration->Settings to gain access to this option.|, 'are_met' => sub{ my $conf = new FS::conf; my @conf_info = qsearch('conf', { 'name' => 'cancel_credit_type' } ); return 1 if (exists($conf_info[0]) && $conf_info[0]->{Hash}{value}); return 0; } } }; foreach my $field ( grep $_ !~ /^(setup|recur)_fee$/, @fields ) { if(!exists($href->{$field})) { # shouldn't happen warn "nonexistent part_pkg option: '$field'\n"; next; } if ( exists($href->{$field}->{display_if}) ) { my %args = ( 'plan' => $layer ); # anything else? my $display = &{ $href->{$field}->{display_if} }(%args); next if !$display; } $html .= ''. $href->{$field}{'name'}. ' '; my $format = sub { shift }; $format = $href->{$field}{'format'} if exists($href->{$field}{'format'}); #XXX these should use elements/ fields... (or this whole thing should #just use layer_fields instead of layer_callback) if (exists($dependencies->{$field}) && !$dependencies->{$field}{'are_met'}()) { $html .= q!N/A!; } elsif ( ! exists($href->{$field}{'type'}) ) { $html .= qq!!; } elsif ( $href->{$field}{'type'} eq 'textarea' ) { $html .= qq!!; } elsif ( $href->{$field}{'type'} eq 'checkbox' ) { $html .= qq!'; } elsif ( $href->{$field}{'type'} eq 'date' ) { $html .= include('/elements/input-date-field.html', { 'name' => $layer.'__'.$field, 'value' => $options{$field}, }); } elsif ( $href->{$field}{'type'} =~ /^select-rt-/ ) { $html .= include('/elements/'.$href->{$field}{'type'}.'.html', 'name' => $layer.'__'.$field, 'curr_value' => $options{$field}, map { $_ => $href->{$field}{$_} } grep { $_ !~ /^(name|type|parse)$/ } keys %{ $href->{$field} } ); } elsif ( $href->{$field}{'type'} eq 'select-rate' ) { $html .= include('/elements/select-rate.html', 'field' => $layer.'__'.$field, 'curr_value' => $options{$field}, map { $_ => $href->{$field}{$_} } grep { $_ !~ /^(name|type)$/ } keys %{ $href->{$field} } ); } elsif ( $href->{$field}{'type'} =~ /^select/ ) { $html .= '{$field}{'type'} eq 'select_multiple'; $html .= qq! NAME="${layer}__$field">!; $html .= '