1# Vend::Options - Interchange item options base module 2# 3# $Id: Options.pm,v 2.8 2007-08-09 13:40:53 pajamian Exp $ 4# 5# Copyright (C) 2002-2007 Interchange Development Group 6# Copyright (C) 1996-2002 Red Hat, Inc. 7# 8# This program is free software; you can redistribute it and/or modify 9# it under the terms of the GNU General Public License as published by 10# the Free Software Foundation; either version 2 of the License, or 11# (at your option) any later version. 12# 13# This program is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU General Public License for more details. 17# 18# You should have received a copy of the GNU General Public 19# License along with this program; if not, write to the Free 20# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21# MA 02110-1301 USA. 22 23package Vend::Options; 24require Exporter; 25 26$VERSION = substr(q$Revision: 2.8 $, 10); 27 28@ISA = qw(Exporter); 29 30@EXPORT = qw( 31 find_joiner 32 find_options_type 33 find_sort 34 inventory_function 35 option_cost 36 remap_option_record 37 ); 38 39use Vend::Util; 40use Vend::Data; 41use Vend::Interpolate; 42use strict; 43 44sub remap_option_record { 45 my ($record, $map) = @_; 46 47 my %rec; 48 my @del; 49 my ($k, $v); 50 while (($k, $v) = each %$map) { 51 next unless defined $record->{$v}; 52 $rec{$k} = $record->{$v}; 53 push @del, $v; 54 } 55 delete @{$record}{@del}; 56 @{$record}{keys %rec} = (values %rec); 57 58 return; 59} 60 61sub find_options_type { 62 my ($item, $opt) = @_; 63 64 my $attrib; 65 return $item->{$attrib} 66 if $attrib = $Vend::Cfg->{OptionsAttribute} 67 and defined $item->{$attrib}; 68 69 my $sku = $item->{mv_sku} || $item->{code}; 70 71 $opt = get_option_hash($opt); 72 73 my $module; 74 75 if($Vend::Cfg->{OptionsEnable}) { 76 my ($tab, $field) = split /:+/, $Vend::Cfg->{OptionsEnable}; 77 if(! $field) { 78 $field = $tab; 79 undef $tab; 80 } 81 elsif($tab =~ /=/) { 82 my $att; 83 ($att, $tab) = split /\s*=\s*/, $tab; 84 $attrib ||= $att; 85 } 86 $attrib ||= $field; 87 $Vend::Cfg->{OptionsAttribute} ||= $attrib; 88 89 if(! defined $item->{$attrib}) { 90 $tab = $item->{mv_ib} || product_code_exists_tag($sku) 91 or do { 92 logOnce('error', "options: Unknown product %s.", $sku); 93 return; 94 }; 95 $item->{$attrib} = tag_data($tab, $field, $sku); 96 } 97 $module = $item->{$attrib} || ''; 98 } 99 else { 100 ## Old style options 101 my $loc = $Vend::Cfg->{Options_repository}{Old48} || {}; 102 my $table = $opt->{table} 103 ||= ( 104 $loc->{table} || $::Variable->{MV_OPTION_TABLE} || 'options' 105 ); 106 my $db = $Vend::Interpolate::Db{$table} || database_exists_ref($table) 107 or return; 108 $db->record_exists($sku) 109 or return; 110 my $record = $opt->{options_record} = $db->row_hash($sku) 111 or return; 112 $opt->{options_db} = $db; 113 remap_option_record($record, $loc->{map}) 114 if $loc->{remap}; 115 116 return '' unless $record->{o_enable}; 117 118 $module = 'Old48'; 119 120 if($record->{o_matrix}) { 121 $opt->{display_routine} 122 = 'Vend::Options::Old48::display_options_matrix'; 123 } 124 elsif($record->{o_modular}) { 125 $module = 'Modular'; 126 } 127 else { 128 $opt->{display_routine} 129 = 'Vend::Options::Old48::display_options_simple'; 130 } 131 } 132 133 return $module; 134} 135 136sub inventory_function { 137 my $opt = shift; 138 return unless $opt->{inventory}; 139 my $inv_func; 140 my ($t, $c) = split /[.:]+/, $opt->{inventory}; 141 my $idb; 142 if($idb = database_exists_ref($t)) { 143 $inv_func = $idb->field_accessor($c); 144 } 145 return $inv_func; 146} 147 148sub find_joiner { 149 my $opt = shift; 150 if($opt->{report}) { 151 $opt->{joiner} ||= ', '; 152 $opt->{separator} ||= ': '; 153 $opt->{type} ||= 'display'; 154 } 155 else { 156 $opt->{joiner} ||= "<br$Vend::Xtrailer>"; 157 } 158 return; 159} 160 161sub find_sort { 162 my $opt = shift; 163 my $db = shift; 164 my $loc = shift || $Vend::Cfg->{Options_repository}{$opt->{options_type}} || {}; 165#::logDebug("called find_sort from " . scalar(caller()) . ", opt=" . ::uneval($opt)); 166 $opt->{sort} = defined $opt->{sort} ? $opt->{sort} : $loc->{sort}; 167 return '' unless $opt->{sort}; 168 my @fields = split /\s*,\s*/, $opt->{sort}; 169 my $map = $loc->{map} ||= {}; 170 for(@fields) { 171 my $extra; 172 $extra = ' DESC' if s/\s+(r(?:ev(?:erse)?)?|desc(?:ending)?)//i; 173 $_ = $map->{$_} || $_; 174 unless (defined $db->test_column($_)) { 175 logOnce( 176 "%s options sort field %s does not exist, returning unsorted", 177 'Matrix', 178 $_, 179 ); 180 return undef; 181 } 182 $_ .= $extra if $extra; 183 } 184 185 return "ORDER BY " . join(",", @fields); 186} 187 188sub tag_options { 189 my ($sku, $opt) = @_; 190 my $item; 191 if(ref $sku) { 192 $item = $sku; 193 $sku = $item->{mv_sku} || $item->{code}; 194 } 195 $item ||= { code => $sku }; 196 $opt = get_option_hash($opt); 197 find_joiner($opt); 198 199 my $module = find_options_type($item, $opt) 200 or return ''; 201 $opt->{options_type} = $module; 202#::logDebug("tag_options module=$module"); 203 204 my $loc = $Vend::Cfg->{Options_repository}{$module} || {}; 205 no strict 'refs'; 206 my $routine; 207 if($opt->{admin_page}) { 208 $opt->{routine_description} ||= "admin page"; 209 $routine = $opt->{admin_page_routine} 210 ||= "Vend::Options::${module}::admin_page"; 211 } 212 else { 213 $opt->{routine_description} ||= "display"; 214 $routine = $opt->{display_routine}; 215 $routine ||= $loc->{display_routine} 216 ||= "Vend::Options::${module}::display_options"; 217#::logDebug("tag_options display routine=$routine"); 218 } 219 my $sub = \&{"$routine"}; 220 if(! defined $sub) { 221 ::logOnce( 222 "Options type %s %s routine %s not found, aborting options for %s.", 223 $module, 224 $opt->{routine_description}, 225 $routine, 226 $sku, 227 ); 228 return undef; 229 } 230#::logDebug("main tag_options item=" . ::uneval($item) . ", opt=" . ::uneval($opt)); 231 return $sub->($item, $opt, $loc); 232} 233 234sub option_cost { 235 my ($item, $table, $final) = @_; 236 237 my $module = find_options_type($item) 238 or return undef; 239#::logDebug("price_options module=$module"); 240 my $loc = $Vend::Cfg->{Options_repository}{$module} || {}; 241 return undef if $loc->{no_pricing}; 242 no strict 'refs'; 243 my $routine = $loc->{price_routine}; 244 $routine ||= "Vend::Options::${module}::price_options"; 245 my $sub = \&{"$routine"}; 246#::logDebug("price_options sub=$sub"); 247 248 if(! defined $sub) { 249 ::logOnce( 250 "Options type %s not found, aborting option_cost for %s.", 251 $module, 252 $item->{code}, 253 ); 254 return undef; 255 } 256 return $sub->($item, $table, $final, $loc); 257} 258 2591; 260__END__ 261