# Vend::Options - Interchange item options base module # # Copyright (C) 2002-2007 Interchange Development Group # Copyright (C) 1996-2002 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this program; if not, write to the Free # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, # MA 02110-1301 USA. package Vend::Options; require Exporter; $VERSION = '2.8'; @ISA = qw(Exporter); @EXPORT = qw( find_joiner find_options_type find_sort inventory_function option_cost remap_option_record ); use Vend::Util; use Vend::Data; use Vend::Interpolate; use strict; sub remap_option_record { my ($record, $map) = @_; my %rec; my @del; my ($k, $v); while (($k, $v) = each %$map) { next unless defined $record->{$v}; $rec{$k} = $record->{$v}; push @del, $v; } delete @{$record}{@del}; @{$record}{keys %rec} = (values %rec); return; } sub find_options_type { my ($item, $opt) = @_; my $attrib; return $item->{$attrib} if $attrib = $Vend::Cfg->{OptionsAttribute} and defined $item->{$attrib}; my $sku = $item->{mv_sku} || $item->{code}; return unless defined $sku && $sku ne ''; $opt = get_option_hash($opt); my $module; if($Vend::Cfg->{OptionsEnable}) { my ($tab, $field) = split /:+/, $Vend::Cfg->{OptionsEnable}; if(! $field) { $field = $tab; undef $tab; } elsif($tab =~ /=/) { my $att; ($att, $tab) = split /\s*=\s*/, $tab; $attrib ||= $att; } $attrib ||= $field; $Vend::Cfg->{OptionsAttribute} ||= $attrib; if(! defined $item->{$attrib}) { $tab = $item->{mv_ib} || product_code_exists_tag($sku) or do { logOnce('error', "options: Unknown product %s.", $sku); return; }; $item->{$attrib} = tag_data($tab, $field, $sku); } $module = $item->{$attrib} || ''; } else { ## Old style options my $loc = $Vend::Cfg->{Options_repository}{Old48} || {}; my $table = $opt->{table} ||= ( $loc->{table} || $::Variable->{MV_OPTION_TABLE} || 'options' ); my $db = $Vend::Interpolate::Db{$table} || database_exists_ref($table) or return; $db->record_exists($sku) or return; my $record = $opt->{options_record} = $db->row_hash($sku) or return; $opt->{options_db} = $db; remap_option_record($record, $loc->{map}) if $loc->{remap}; return '' unless $record->{o_enable}; $module = 'Old48'; if($record->{o_matrix}) { $opt->{display_routine} = 'Vend::Options::Old48::display_options_matrix'; } elsif($record->{o_modular}) { $module = 'Modular'; } else { $opt->{display_routine} = 'Vend::Options::Old48::display_options_simple'; } } return $module; } sub inventory_function { my $opt = shift; return unless $opt->{inventory}; my $inv_func; my ($t, $c) = split /[.:]+/, $opt->{inventory}; my $idb; if($idb = database_exists_ref($t)) { $inv_func = $idb->field_accessor($c); } return $inv_func; } sub find_joiner { my $opt = shift; if($opt->{report}) { $opt->{joiner} ||= ', '; $opt->{separator} ||= ': '; $opt->{type} ||= 'display'; } else { $opt->{joiner} ||= ""; } return; } sub find_sort { my $opt = shift; my $db = shift; my $loc = shift || $Vend::Cfg->{Options_repository}{$opt->{options_type}} || {}; #::logDebug("called find_sort from " . scalar(caller()) . ", opt=" . ::uneval($opt)); $opt->{sort} = defined $opt->{sort} ? $opt->{sort} : $loc->{sort}; return '' unless $opt->{sort}; return " ORDER BY $opt->{sort}" if $opt->{rawsort} || $loc->{rawsort}; my @fields = split /\s*,\s*/, $opt->{sort}; my $map = $loc->{map} ||= {}; for(@fields) { my $extra; $extra = ' DESC' if s/\s+(r(?:ev(?:erse)?)?|desc(?:ending)?)//i; $_ = $map->{$_} || $_; unless (defined $db->test_column($_)) { logOnce( "%s options sort field %s does not exist, returning unsorted", 'Matrix', $_, ); return undef; } $_ .= $extra if $extra; } return " ORDER BY " . join(",", @fields); } sub tag_options { my ($sku, $opt) = @_; my $item; if(ref $sku) { $item = $sku; $sku = $item->{mv_sku} || $item->{code}; } $item ||= { code => $sku }; $opt = get_option_hash($opt); find_joiner($opt); my $module = find_options_type($item, $opt) or return ''; $opt->{options_type} = $module; #::logDebug("tag_options module=$module"); my $loc = $Vend::Cfg->{Options_repository}{$module} || {}; no strict 'refs'; my $routine; if($opt->{admin_page}) { $opt->{routine_description} ||= "admin page"; $routine = $opt->{admin_page_routine} ||= "Vend::Options::${module}::admin_page"; } else { $opt->{routine_description} ||= "display"; $routine = $opt->{display_routine}; $routine ||= $loc->{display_routine} ||= "Vend::Options::${module}::display_options"; #::logDebug("tag_options display routine=$routine"); } my $sub = \&{"$routine"}; if(! defined $sub) { ::logOnce( "Options type %s %s routine %s not found, aborting options for %s.", $module, $opt->{routine_description}, $routine, $sku, ); return undef; } #::logDebug("main tag_options item=" . ::uneval($item) . ", opt=" . ::uneval($opt)); return $sub->($item, $opt, $loc); } sub option_cost { my ($item, $table, $final) = @_; my $module = find_options_type($item) or return undef; #::logDebug("price_options module=$module"); my $loc = $Vend::Cfg->{Options_repository}{$module} || {}; return undef if $loc->{no_pricing}; no strict 'refs'; my $routine = $loc->{price_routine}; $routine ||= "Vend::Options::${module}::price_options"; my $sub = \&{"$routine"}; #::logDebug("price_options sub=$sub"); if(! defined $sub) { ::logOnce( "Options type %s not found, aborting option_cost for %s.", $module, $item->{code}, ); return undef; } return $sub->($item, $table, $final, $loc); } 1; __END__