[interchange-cvs] interchange - jon modified 3 files

interchange-cvs at icdevgroup.org interchange-cvs at icdevgroup.org
Mon Nov 7 16:53:55 EST 2005


User:      jon
Date:      2005-11-07 21:53:55 GMT
Modified:  lib/Vend Cart.pm Config.pm Order.pm
Log:
Add new CartTrigger functionality to the core, by Ethan Rowe.

The CartTrigger functionality allows for specification of any number
of subroutines (global or catalog subs, specified by name) to execute
whenever the contents of a shopping cart are changed via the standard
means available through CGI variable space (i.e. when changes are
invoked via the 'process' system actionmap through mv_order_item and
mv_order_quantity field submissions, or from a standard Interchange cart
page). The subroutines will be executed per-change, such that any page
process resulting in multiple alterations to the cart will potentially
call these functions multiple times.

Directives are used to turn this behavior on/off and to control some
details of its behavior:

CartTrigger: an array-type directive; list the different subroutine
names to execute at cart-modification time here.

CartTriggerQuantity: a boolean-type (i.e. yes/no) directive, defaulting
to 'no'/'false'; when set to yes/true, changes to item quantity on an
existing cart member will cause the cart trigger subs to fire. A value
of 'no' (the default) means that quantity changes on existing cart lines
do not call the trigger (though a quantity change to zero will result in
a delete, which does fire the cart trigger).

Each subroutine specified in CartTrigger will be passed the following
arguments whenever they are called:
1. Reference to the cart
2. Scalar representing the action that fired the trigger; value will be
one of: add, update, delete
3. Hashref pointing to the new row (except for the 'delete' action, in
which case this will be undefined)
4. Hashref representing the old row (except for the 'add' action); for
'update' actions, this will be a *copy* of the row prior to the changes.
The old row is no longer a member of the cart.
5. The cart's name

The return value from each subroutine call is pushed onto an array;
when the particular trigger firing is complete (i.e. all subroutines
specified in CartTrigger have been called), the full array of results is
returned. However, the initial version of this functionality does not
use these return values in any meaningful way.

It must be noted that the Interchange cart subsystem is based
on arrayrefs of hashrefs; there is no object encapsulation for
limiting/monitoring programmatic access to the contents of any cart.
Consequently, direct manipulation of the cart from within Perl will
*not* cause these triggers to fire. The triggers only fire when the
cart contents are modified through the standard Interchange CGI-based
variables/processing. Therefore, it is assumed for now that any
programmer sufficiently comfortable/confident to manipulate cart
contents directly can also be given the responsibility of deciding
whether or not it is appropriate to invoke any cart triggers in response
to such changes.

Revision  Changes    Path
2.12      +78 -8     interchange/lib/Vend/Cart.pm


rev 2.12, prev_rev 2.11
Index: Cart.pm
===================================================================
RCS file: /var/cvs/interchange/lib/Vend/Cart.pm,v
retrieving revision 2.11
retrieving revision 2.12
diff -u -u -r2.11 -r2.12
--- Cart.pm	28 Apr 2005 01:54:44 -0000	2.11
+++ Cart.pm	7 Nov 2005 21:53:55 -0000	2.12
@@ -1,6 +1,6 @@
 # Vend::Cart - Interchange shopping cart management routines
 #
-# $Id: Cart.pm,v 2.11 2005/04/28 01:54:44 mheins Exp $
+# $Id: Cart.pm,v 2.12 2005/11/07 21:53:55 jon Exp $
 #
 # Copyright (C) 2002-2003 Interchange Development Group
 # Copyright (C) 1996-2002 Red Hat, Inc.
@@ -25,7 +25,7 @@
 
 package Vend::Cart;
 
-$VERSION = substr(q$Revision: 2.11 $, 10);
+$VERSION = substr(q$Revision: 2.12 $, 10);
 
 use strict;
 
@@ -180,6 +180,11 @@
 	my $sub;
 	my (@master);
 	my (@cascade);
+	my ($raise_event, $quantity_raise_event)
+		= @{$Vend::Cfg}{qw/CartTrigger CartTriggerQuantity/};
+	$quantity_raise_event = $raise_event && $quantity_raise_event;
+	my $event_cartname = $cartname || $Vend::CurrentCart;
+	my $old_item;
 	DELETE: for (;;) {
 		foreach $i (0 .. $#$s) {
 			my $item = $s->[$i];
@@ -195,7 +200,13 @@
 				elsif ( $item->{mv_ci} ) {
 					push (@master, $item->{mv_ci});
 				}
+				$old_item = $s->[$i] if $raise_event;
 				splice(@$s, $i, 1);
+				trigger_delete(
+						$s,
+						$old_item,
+						$event_cartname
+					) if $raise_event;
 				next DELETE;
 			}
 
@@ -216,8 +227,15 @@
 					$item->{quantity} < $item->{mv_min_quantity}
 					)
 				{
+					$old_item = { %$item } if $quantity_raise_event;
 					$item->{quantity} = $item->{mv_min_quantity};
 					$item->{mv_min_under} = 1;
+					trigger_update(
+							$s,
+							$item,
+							$old_item,
+							$event_cartname
+						) if $quantity_raise_event;
 				}
 			}
 
@@ -235,18 +253,25 @@
 					$item->{quantity} > $item->{mv_max_quantity}
 					)
 				{
+					$old_item = { %$item } if $quantity_raise_event;
 					$item->{quantity} = $item->{mv_max_quantity};
 					$item->{mv_max_over} = 1;
+					trigger_update(
+							$s,
+							$item,
+							$old_item,
+							$event_cartname
+						) if $quantity_raise_event;
 				}
 			}
 
-			next unless $Vend::Cfg->{Limit}{cart_quantity_per_line};
+			next unless $Vend::Cfg->{Limit}{cart_quantity_per_line}
+				and $item->{quantity} > $Vend::Cfg->{Limit}{cart_quantity_per_line};
 			
-			$item->{quantity} = $Vend::Cfg->{Limit}{cart_quantity_per_line}
-				if
-					$item->{quantity}
-						>
-					$Vend::Cfg->{Limit}{cart_quantity_per_line};
+			$old_item = { %$item } if $quantity_raise_event;				
+			$item->{quantity} = $Vend::Cfg->{Limit}{cart_quantity_per_line};
+			trigger_update( $s, $item, $old_item, $event_cartname )
+				if $quantity_raise_event;
 		}
 		last DELETE;
 	}
@@ -275,6 +300,10 @@
 			}
 			@items = @$s;
 			@{$s} = @items[sort {$a <=> $b} keys %save];
+			if ($raise_event and scalar(@items) > scalar(@$s)) {
+				trigger_delete($s, $items[$_], $event_cartname)
+					for grep { ! $save{$_} } (0..$#items);
+			}
 		}
 	}
 	Vend::Interpolate::levies(1, $cartname);
@@ -293,6 +322,47 @@
 	# ENDTEST
 
 =cut
+
+sub trigger_event {
+	my($s, $action, $new_row, $old_row, $cartname) = @_;
+	return unless my $subs = $Vend::Cfg->{CartTrigger};
+	$subs = [ split /\s+/, $subs ] unless ref $subs eq 'ARRAY';
+	my @results;
+	for my $subname (@$subs) {
+		next unless my $sub
+			= $Vend::Cfg->{Sub}{$subname}
+			|| $Global::GlobalSub->{$subname};
+
+		my $result;
+		eval {
+			$result = $sub->($s, $action, $new_row, $old_row, $cartname);
+		};
+		if ($@) {
+			::logError( "CartTrigger event handler '%' action '%' returned error:\n%",
+				$Vend::Cfg->{CartTrigger},
+				$action,
+				$@ );
+			$result = undef;
+		}
+		push @results, $result
+	}
+	return @results;
+}
+
+sub trigger_add {
+	my($s,$new_row,$cartname) = @_;
+	return trigger_event($s, 'add', $new_row, undef, $cartname);
+}
+
+sub trigger_update {
+	my($s,$new_row,$old_row,$cartname) = @_;
+	return trigger_event($s, 'update', $new_row, $old_row, $cartname);
+}
+
+sub trigger_delete {
+	my($s,$old_row,$cartname) = @_;
+	return trigger_event($s, 'delete', undef, $old_row, $cartname);
+}
 
 1;
 



2.188     +4 -2      interchange/lib/Vend/Config.pm


rev 2.188, prev_rev 2.187
Index: Config.pm
===================================================================
RCS file: /var/cvs/interchange/lib/Vend/Config.pm,v
retrieving revision 2.187
retrieving revision 2.188
diff -u -u -r2.187 -r2.188
--- Config.pm	7 Nov 2005 21:40:40 -0000	2.187
+++ Config.pm	7 Nov 2005 21:53:55 -0000	2.188
@@ -1,6 +1,6 @@
 # Vend::Config - Configure Interchange
 #
-# $Id: Config.pm,v 2.187 2005/11/07 21:40:40 jon Exp $
+# $Id: Config.pm,v 2.188 2005/11/07 21:53:55 jon Exp $
 #
 # Copyright (C) 2002-2005 Interchange Development Group
 # Copyright (C) 1996-2002 Red Hat, Inc.
@@ -52,7 +52,7 @@
 use Vend::Data;
 use Vend::Cron;
 
-$VERSION = substr(q$Revision: 2.187 $, 10);
+$VERSION = substr(q$Revision: 2.188 $, 10);
 
 my %CDname;
 my %CPname;
@@ -703,6 +703,8 @@
 	['XHTML',			 'yesno',	     	 $Global::XHTML],
 	['External',		 'yesno',	     	 'No'],
 	['ExternalExport',	 undef,		     	 join " ", @External_directives],
+	['CartTrigger',		 'routine_array',	 ''],
+	['CartTriggerQuantity',	'yesno',		 'no'],
 
 	];
 



2.82      +56 -8     interchange/lib/Vend/Order.pm


rev 2.82, prev_rev 2.81
Index: Order.pm
===================================================================
RCS file: /var/cvs/interchange/lib/Vend/Order.pm,v
retrieving revision 2.81
retrieving revision 2.82
diff -u -u -r2.81 -r2.82
--- Order.pm	1 Nov 2005 11:14:49 -0000	2.81
+++ Order.pm	7 Nov 2005 21:53:55 -0000	2.82
@@ -1,6 +1,6 @@
 # Vend::Order - Interchange order routing routines
 #
-# $Id: Order.pm,v 2.81 2005/11/01 11:14:49 racke Exp $
+# $Id: Order.pm,v 2.82 2005/11/07 21:53:55 jon Exp $
 #
 # Copyright (C) 2002-2003 Interchange Development Group
 # Copyright (C) 1996-2002 Red Hat, Inc.
@@ -29,7 +29,7 @@
 package Vend::Order;
 require Exporter;
 
-$VERSION = substr(q$Revision: 2.81 $, 10);
+$VERSION = substr(q$Revision: 2.82 $, 10);
 
 @ISA = qw(Exporter);
 
@@ -2095,15 +2095,20 @@
 sub update_quantity {
     return 1 unless defined  $CGI::values{"quantity0"}
 		|| $CGI::values{mv_quantity_update};
-	my($h, $i, $quantity, $modifier, $cart);
+	my ($h, $i, $quantity, $modifier, $cart, $cartname, %altered_items, %old_items);
 
 	if ($CGI::values{mv_cartname}) {
-		$cart = $::Carts->{$CGI::values{mv_cartname}} ||= [];
+		$cart = $::Carts->{$cartname = $CGI::values{mv_cartname}} ||= [];
 	}
 	else {
 		$cart = $Vend::Items;
+		$cartname = $Vend::CurrentCart;
 	}
 
+	my ($raise_event, $quantity_raise_event)
+		= @{$Vend::Cfg}{qw/CartTrigger CartTriggerQuantity/};
+	$quantity_raise_event = $raise_event && $quantity_raise_event;
+
 	my @mods;
 	@mods = @{$Vend::Cfg->{UseModifier}} if $Vend::Cfg->{UseModifier};
 
@@ -2123,6 +2128,7 @@
 			next if
 				!   defined $CGI::values{"$h$i"}
 				and defined $cart->[$i]{$h};
+			$old_items{$i} ||= { %{$cart->[$i]} } if $raise_event;
 			$modifier = $CGI::values{"$h$i"}
 					  || (defined $cart->[$i]{$h} ? '' : undef);
 #::logDebug("line $i modifier $h now $modifier");
@@ -2131,6 +2137,9 @@
 				$modifier =~ s/\0$//;
 				$modifier =~ s/^\0//;
 				$modifier =~ s/\0/, /g;
+				$altered_items{$i} = 1
+					if $raise_event
+					and $cart->[$i]->{$h} ne $modifier;
 				$cart->[$i]->{$h} = $modifier;
 				$::Values->{"$h$i"} = $modifier;
 				delete $CGI::values{"$h$i"};
@@ -2145,14 +2154,21 @@
     	$quantity = $CGI::values{"quantity$i"};
     	next unless defined $quantity;
 		my $do_update;
+		my $old_item = $old_items{$i} ||= { %$line } if $raise_event;
     	if ($quantity =~ m/^\d*$/) {
         	$line->{'quantity'} = $quantity || 0;
 			$do_update = 1;
+			$altered_items{$i} = 1
+				if $quantity_raise_event
+				and $line->{quantity} != $old_item->{quantity};
     	}
     	elsif ($quantity =~ m/^[\d.]+$/
 				and $Vend::Cfg->{FractionalItems} ) {
         	$line->{'quantity'} = $quantity;
 			$do_update = 1;
+			$altered_items{$i} = 1
+				if $quantity_raise_event
+				and $line->{quantity} != $old_item->{quantity};
     	}
 		# This allows a last-positioned input of item quantity to
 		# remove the item
@@ -2234,9 +2250,17 @@
 				else {
 					$line->{code}	= $sku;
 				}
+				$altered_items{$i} = 1 if $raise_event;
 			}
 		}
-    }
+	}
+
+	Vend::Cart::trigger_update(
+			$cart,
+			$cart->[$_], # new item version
+			$old_items{$_}, # old item version
+			$cartname
+		) for sort { $a <=> $b } keys %altered_items;
 #::logDebug("after update, cart is: " . ::uneval($cart));
 
 	# If the user has put in "0" for any quantity, delete that item
@@ -2271,14 +2295,19 @@
 
 	::update_quantity() if ! defined $CGI::values{mv_orderline};
 
-	my $cart;
-	if($CGI::values{mv_cartname}) {
-		$cart = $::Carts->{$CGI::values{mv_cartname}} ||= [];
+	my ($cart, $cartname);
+	if ($cartname = $CGI::values{mv_cartname}) {
+		$cart = $::Carts->{$cartname} ||= [];
 	}
 	else {
 		$cart = $Vend::Items;
+		$cartname = $Vend::CurrentCart;
 	}
 
+	my ($raise_event,$track_quantity)
+		= @{$Vend::Cfg}{qw/CartTrigger CartTriggerQuantity/};
+	$raise_event = @$raise_event if ref $raise_event eq 'ARRAY';
+
 	@items      = split /\0/, ($items);
 	@quantities = split /\0/, ($quantities || delete $CGI::values{mv_order_quantity} || '');
 	@bases      = split /\0/, delete $CGI::values{mv_order_mv_ib}
@@ -2415,7 +2444,14 @@
 					# Increment quantity. This is different than
 					# the standard handling because we are ordering
 					# accessories, and may want more than 1 of each
+					my %old_item = %{$cart->[$i]} if $raise_event and $track_quantity;
 					$cart->[$i]{quantity} = $set ? $quantity : $cart->[$i]{quantity} + $quantity;
+					Vend::Cart::trigger_update(
+							$cart,
+							$cart->[$i], # new row
+							\%old_item, # old row
+							$cartname
+						) if $raise_event and $track_quantity;
 				}
 			}
 		} # INCREMENT
@@ -2504,13 +2540,25 @@
 			}
 
 			if($lines[$j] =~ /^\d+$/ and defined $cart->[$lines[$j]] ) {
+				my %old = %{$cart->[$lines[$j]]} if $raise_event;
 				$cart->[$lines[$j]] = $item;
+				Vend::Cart::trigger_update(
+						$cart,
+						$item, # new item
+						\%old, # old item
+						$cartname,
+					) if $raise_event;
 			}
 			else {
 # TRACK
 				$Vend::Track->add_item($cart,$item) if $Vend::Track;
 # END TRACK
 				push @$cart, $item;
+				Vend::Cart::trigger_add(
+						$cart,
+						$item, # new item
+						$cartname,
+					) if $raise_event;
 			}
 		}
 		$j++;








More information about the interchange-cvs mailing list