* Add enclair_db option to UserDB.pm. Allows logging of enclair password
[interchange.git] / lib / Vend / Options / Old48.pm
1 # Vend::Options::Old48 - Interchange 4.8 compatible product options
2 #
3 # $Id: Old48.pm,v 1.14 2007-08-09 13:40:55 pajamian Exp $
4 #
5 # Copyright (C) 2002-2007 Interchange Development Group <interchange@icdevgroup.org>
6 # Copyright (C) 2002-2003 Mike Heins <mikeh@perusion.net>
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 #
23
24 package Vend::Options::Old48;
25
26 $VERSION = substr(q$Revision: 1.14 $, 10);
27
28 =head1 NAME
29
30 Vend::Options::Old48 - Interchange Compatibility Options Support
31
32 =head1 SYNOPSIS
33
34     [item-options]
35  
36         or
37  
38     [price code=SKU]
39  
40 =head1 PREREQUISITES
41
42 Vend::Options
43
44 =head1 DESCRIPTION
45
46 The Vend::Options::Old48 module implements simple and matrix product
47 options for Interchange. It is compatible with Interchange 4.8.x
48 matrix options. Newer versions use Simple and Matrix options instead.
49
50 If the Interchange Variable MV_OPTION_TABLE is not set, it defaults
51 to "options", which combines options for Simple, Matrix, and
52 Modular into that one table. This goes along with foundation and
53 construct demos up until Interchange 4.9.8.
54
55 The "options" table remains the default for matrix options.
56
57 =head1 AUTHORS
58
59 Mike Heins <mikeh@perusion.net>
60
61 =head1 CREDITS
62
63     Jon Jensen <jon@swelter.net>
64
65 =cut
66
67 use Vend::Util;
68 use Vend::Data;
69 use Vend::Interpolate;
70 use Vend::Options;
71
72 sub option_cost {
73         my ($item, $opt) = @_;
74
75 }
76
77 sub display_options_matrix {
78         my ($item, $opt, $loc) = @_;
79
80         $loc ||= $Vend::Cfg->{Options_repository}{Old48} || \%Default;
81 #::logDebug("Matrix options by module, old");
82         my $sku = $item->{mv_sku} || $item->{code};
83         my $db;
84         my $tab;
85
86         if(not $db = $opt->{options_db}) {
87                 $tab = $opt->{table} || $::Variable->{MV_OPTION_TABLE} || 'options';
88                 $db = database_exists_ref($tab)
89                         or do {
90                                 logOnce(
91                                                 "Matrix options: unable to find table %s for item %s",
92                                                 $tab,
93                                                 $sku,
94                                         );
95                                 return undef;
96                         };
97         }
98
99         my $record;
100         if(not $record = $opt->{options_record}) {
101                 $db->record_exists($sku)
102                         or do {
103                                 logOnce(
104                                         "Matrix options: unable to find record in table %s for item %s",
105                                         $tab,
106                                         $sku,
107                                 );
108                                 return;
109                         };
110                 $record = $db->row_hash($sku) || {};
111         }
112
113         my $tname = $db->name();
114
115         if(not $opt->{display_type} ||= $record->{display_type}) {
116                 $opt->{display_type} = $record->{o_matrix} == 2 ? 'separate' : 'single';
117         }
118
119         $opt->{display_type} = lc $opt->{display_type};
120
121         my $map;
122         if(not $map = $opt->{options_map}) {
123                 $map = $opt->{options_map} = {};
124                 if(my $remap = $opt->{remap} || $::Variable->{MV_OPTION_TABLE_MAP}) {
125                         remap_option_record($record, $map, $remap);
126                 }
127         }
128
129         my @rf;
130         my @out;
131         my $out;
132         
133     my $inv_func;
134     if($opt->{inventory}) {
135         my ($tab, $col) = split /:+/, $opt->{inventory};
136         MAKEFUNC: {
137             my $idb = dbref($tab)
138                 or do {
139                     logError("Bad table %s for inventory function.", $tab);
140                     last MAKEFUNC;
141                 };
142             $idb->test_column($col)
143                 or do {
144                     logError(
145                         "Bad column %s in table %s for inventory function.",
146                         $col,
147                         $tab,
148                     );
149                     last MAKEFUNC;
150                 };
151             $inv_func = sub {
152                 my $key = shift;
153                 return $idb->field($key, $col);
154             };
155         }
156     }
157
158         my $rsort = find_sort($opt, $db, $loc);
159
160         if($opt->{display_type} eq 'separate') {
161                 for(qw/code o_enable o_group o_value o_label o_widget price/) {
162                         push @rf, ($map->{$_} || $_);
163                 }
164                 my @def;
165                 if($item and $item->{code}) {
166                         @def = split /-/, $item->{code};
167                 }
168                 my $fsel = $map->{sku} || 'sku';
169                 my $rsel = $db->quote($sku, $fsel);
170                 
171                 my $q = "SELECT " .
172                                 join (",", @rf) .
173                                 " FROM $tname where $fsel = $rsel $rsort";
174 #::logDebug("tag_options matrix query: $q");
175                 my $ary = $db->query($q); 
176 #::logDebug("tag_options matrix ary: " . ::uneval($ary));
177                 my $ref;
178                 my $i = 0;
179                 my $phony = { %{$item || { }} };
180                 foreach $ref (@$ary) {
181
182                         next unless $ref->[3];
183
184                         # skip based on inventory if enabled
185                         if($inv_func) {
186                                 my $oh = $inv_func->($ref->[0]);
187                                 next if $oh <= 0;
188                         }
189
190                         $i++;
191
192                         # skip unless o_value
193                         $phony->{mv_sku} = $def[$i];
194
195                         if ($opt->{label}) {
196                                 $ref->[4] = "<b>$ref->[4]</b>" if $opt->{bold};
197                                 push @out, $ref->[4];
198                         }
199                         push @out, Vend::Interpolate::tag_accessories(
200                                                         $sku,
201                                                         '',
202                                                         { 
203                                                                 passed => $ref->[3],
204                                                                 type => $opt->{type} || $ref->[5] || 'select',
205                                                                 attribute => 'mv_sku',
206                                                                 price_data => $ref->[6],
207                                                                 price => $opt->{price},
208                                                                 extra => $opt->{extra},
209                                                                 js => $opt->{js},
210                                                                 item => $phony,
211                                                         },
212                                                         $phony || undef,
213                                                 );
214                 }
215                 
216                 $phony->{mv_sku} = $sku;
217                 my $begin = Vend::Interpolate::tag_accessories(
218                                                         $sku,
219                                                         '',
220                                                         { 
221                                                                 type => 'hidden',
222                                                                 attribute => 'mv_sku',
223                                                                 item => $phony,
224                                                                 default => $sku,
225                                                         },
226                                                         $phony,
227                                                 );
228                 if($opt->{td}) {
229                         for(@out) {
230                                 $out .= "<td>$begin$_</td>";
231                                 $begin = '';
232                         }
233                 }
234                 else {
235                         $opt->{joiner} = "<br$Vend::Xtrailer>" if ! $opt->{joiner};
236                         $out .= $begin;
237                         $out .= join $opt->{joiner}, @out;
238                 }
239         }
240         else {
241                 for(qw/code o_enable o_group description price weight volume differential o_widget/) {
242                         push @rf, ($map->{$_} || $_);
243                 }
244                 my $ccol = $map->{code} || 'code';
245                 my $lcol = $map->{sku} || 'sku';
246                 my $lval = $db->quote($sku, $lcol);
247
248                 my $q = "SELECT " . join(",", @rf);
249                 $q .= " FROM $tname where $lcol = $lval AND $ccol <> $lval $rsort";
250 #::logDebug("tag_options matrix query: $q");
251                 my $ary = $db->query($q); 
252 #::logDebug("tag_options matrix ary: " . ::uneval($ary));
253                 my $ref;
254                 my $price = {};
255                 foreach $ref (@$ary) {
256                         # skip unless description
257                         next unless $ref->[3];
258
259                         # skip based on inventory if enabled
260                         if($inv_func) {
261                                 my $oh = $inv_func->($ref->[0]);
262                                 next if $oh <= 0;
263                         }
264
265                         $ref->[3] =~ s/,/&#44;/g;
266                         $ref->[3] =~ s/=/&#61;/g;
267                         $price->{$ref->[0]} = $ref->[4];
268                         push @out, "$ref->[0]=$ref->[3]";
269                 }
270                 $out .= "<td>" if $opt->{td};
271                 $out .= Vend::Interpolate::tag_accessories(
272                                                         $sku,
273                                                         '',
274                                                         { 
275                                                                 attribute => 'code',
276                                                                 default => undef,
277                                                                 extra => $opt->{extra},
278                                                                 item => $item,
279                                                                 js => $opt->{js},
280                                                                 name => 'mv_sku',
281                                                                 passed => join(",", @out),
282                                                                 price => $opt->{price},
283                                                                 price_data => $price,
284                                                                 type => $opt->{type} || $ref->[8] || 'select',
285                                                         },
286                                                         $item || undef,
287                                                 );
288                 $out .= "</td>" if $opt->{td};
289 #::logDebug("matrix option returning $out");
290         }
291
292         return $out;
293 }
294
295 sub price_options {
296         my ($item, $table, $final, $loc) = @_;
297
298 #::logDebug("option_cost table=$table");
299         $loc ||= $Vend::Cfg->{Options_repository}{Old48} || {};
300
301         my $sku = $item->{mv_sku} || $item->{code};
302         my $db = database_exists_ref($table)
303                 or return undef;
304 #::logDebug("option_cost db=$db");
305
306         my $map = $loc->{map} || {};
307         my $fsel = $map->{sku} || 'sku';
308         my $rsel = $db->quote($sku, $fsel);
309         my @rf;
310         for(qw/o_group price/) {
311                 push @rf, ($map->{$_} || $_);
312         }
313
314         my $q = "SELECT " . join (",", @rf) . " FROM $table WHERE $fsel = $rsel";
315 #::logDebug("option_cost query=$q");
316         my $ary = $db->query($q); 
317         return if ! $ary->[0];
318         my $ref;
319         my $price = 0;
320         my $f;
321
322         foreach $ref (@$ary) {
323 #::logDebug("checking option " . uneval_it($ref));
324                 next unless defined $item->{$ref->[0]};
325                 $ref->[1] =~ s/^\s+//;
326                 $ref->[1] =~ s/\s+$//;
327                 $ref->[1] =~ s/==/=:/g;
328                 my %info = split /\s*[=,]\s*/, $ref->[1];
329                 if(defined $info{ $item->{$ref->[0]} } ) {
330                         my $atom = $info{ $item->{$ref->[0]} };
331                         if($atom =~ s/^://) {
332                                 $f = $atom;
333                                 next;
334                         }
335                         elsif ($atom =~ s/\%$//) {
336                                 $f = $final if ! defined $f;
337                                 $f += ($atom * $final / 100);
338                         }
339                         else {
340                                 $price += $atom;
341                         }
342                 }
343         }
344 #::logDebug("option_cost returning price=$price f=$f");
345         return ($price, $f);
346 }
347
348 sub display_options_simple {
349         my ($item, $opt) = @_;
350 #::logDebug("Simple options, item=" . ::uneval($item) . "\nopt=" . ::uneval($opt));
351         my $map = $opt->{options_map} ||= {};
352 #::logDebug("Simple options by module, old");
353
354         my $sku = $item->{code};
355         my $db;
356         my $tab;
357         if(not $db = $opt->{options_db}) {
358                 $tab = $opt->{table} ||= $::Variable->{MV_OPTION_TABLE_SIMPLE}
359                                                          ||= $::Variable->{MV_OPTION_TABLE}
360                                                          ||= 'options';
361                 $db = database_exists_ref($tab)
362                         or do {
363                                 logOnce(
364                                                 "Simple options: unable to find table %s for item %s",
365                                                 $tab,
366                                                 $sku,
367                                         );
368                                 return undef;
369                         };
370         }
371
372         my $tname = $db->name();
373
374         my @rf;
375         my @out;
376         my $out;
377
378         my $ishash = defined $item->{mv_ip} ? 1 : 0;
379
380         for(qw/code o_enable o_group o_value o_label o_widget price o_height o_width/) {
381                 push @rf, ($map->{$_} || $_);
382         }
383
384         my $fsel = $map->{sku} || 'sku';
385         my $rsel = $db->quote($sku, $fsel);
386         
387         my $q = "SELECT " . join (",", @rf) . " FROM $tname where $fsel = $rsel";
388
389         if(my $rsort = find_sort($opt, $db, $loc)) {
390                 $q .= " $rsort";
391         }
392 #::logDebug("tag_options simple query: $q");
393
394         my $ary = $db->query($q)
395                 or return; 
396
397         my $ref;
398         foreach $ref (@$ary) {
399                 # skip unless o_value
400                 next unless $ref->[3];
401                 if ($opt->{label}) {
402                         $ref->[4] = "<b>$ref->[4]</b>" if $opt->{bold};
403                         push @out, $ref->[4];
404                 }
405                 my $precursor = $opt->{report}
406                                           ? "$ref->[2]$opt->{separator}"
407                                           : qq{<input type="hidden" name="mv_item_option" value="$ref->[2]">};
408                 push @out, $precursor . Vend::Interpolate::tag_accessories(
409                                                 $sku,
410                                                 '',
411                                                 { 
412                                                         attribute => $ref->[2],
413                                                         default => undef,
414                                                         extra => $opt->{extra},
415                                                         item => $item,
416                                                         name => $ishash ? undef : "mv_order_$ref->[2]",
417                                                         js => $opt->{js},
418                                                         passed => $ref->[3],
419                                                         price => $opt->{price},
420                                                         price_data => $ref->[6],
421                                                         height => $opt->{height} || $ref->[7],
422                                                         width  => $opt->{width} || $ref->[8],
423                                                         type => $opt->{type} || $ref->[5] || 'select',
424                                                 },
425                                                 $item || undef,
426                                         );
427         }
428         if($opt->{td}) {
429                 for(@out) {
430                         $out .= "<td>$_</td>";
431                 }
432         }
433         else {
434                 $opt->{joiner} = "<br$Vend::Xtrailer>" if ! $opt->{joiner};
435                 $out .= join $opt->{joiner}, @out;
436         }
437         return $out;
438 }
439
440 *display_options = \&display_options_simple;
441
442 1;