#!/usr/local/bin/perl #?use CGI::Carp qw(fatalsToBrowser); # # Make sure "." is included in the @INC directory list so we can find our packages # my $bFound = 0; my $sDir; foreach $sDir (@INC) { if ($sDir eq ".") { $bFound = 1; last; } } if (!$bFound) { push (@INC, "."); } # # NT systems rarely execute the CGI scripts in the cgi-bin, so attempt to locate # the packages in that case. This may still fail if the cgi-bin folder is named # something else, but at least we will catch 80% of the cases. # push (@INC, "cgi-bin"); require al000000; require ao000000; use strict; ####################################################### # # # The above is the Path to Perl on the ISP's server # # # # Requires Perl version 5.002 or later # # # ####################################################### ####################################################### # # # CATALOG SHOPPING CART CGI/PERL SCRIPT # # # # Copyright (c) 1997 ACTINIC SOFTWARE LIMITED # # # # written by George Menyhert # # # ####################################################### Init(); # initialize the global constants and data structures DispatchCommands(); # process the commands exit; ############################################################################################################## # # Command Processing - Begin # ############################################################################################################## ####################################################### # # DispatchCommands - parse the command input and # call the command processing function # # Expects: %g_InputHash, and %g_SetupBlob # should be defined # ####################################################### sub DispatchCommands { my (@Response, $Status, $Message, $sHTML, $sAction, $sCartID); $::g_sCurrentPage = $::g_InputHash{"PAGE"}; # identify the calling page $sAction = $::g_InputHash{"ACTION"}; # check the page action # # static pages call the shopping cart page via ?ACTION=SHOWCART # static pages call the active X order control page via ?ACTION=ORDERACTIVEX # static pages call the Java order control page via ?ACTION=ORDERJAVA # # All other queries are page specific. NOTE: all queries must contain a PATH # variable that is set to the path from the cgi bin to the web site # my ($key, $value); if ($sAction eq "SHOWCART") # display the shopping cart - this is a { @Response = ShowCart(); ($Status, $Message, $sHTML, $sCartID) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML, $sCartID); } elsif ($::g_sCurrentPage eq "SEARCH") { @Response = SearchPages(); ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) { if ($Status == $::FAILEDSEARCH) { @Response = ReturnToLastPage(3, $Message, "Search"); # bounce back in the broswer ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML); } else { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); } exit; } PrintPage($sHTML, undef, $::FALSE); } elsif ($::g_sCurrentPage eq "CONFIRMREMOVE") # the call was made from a "confirm remove item" page { while (($key, $value) = each %::g_InputHash) # locate the command button { if ($value =~ /$::g_sConfirmButtonLabel/ || # found the "Confirm" button $value =~ /$::g_sCancelButtonLabel/) # or the "Cancel" button { my ($Temp); $Temp = keys %::g_InputHash; # reset the iterator for "each" last; } } if ($value eq $::g_sConfirmButtonLabel) { @Response = RemoveItem(); # remove the item from the cart and redisplay the cart ($Status, $Message, $sHTML, $sCartID) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML, $sCartID); } else { @Response = ReturnToLastPage(0, "", ""); # just redisplay the cart ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML); } } elsif ($::g_sCurrentPage eq "SHOPPINGCART") # the call was made from a shopping cart page { while (($key, $value) = each %::g_InputHash) # locate the command button { if ($value =~ /$::g_sRemoveButtonLabel/ || # found the "Remove" button $value =~ /$::g_sEditButtonLabel/) # or the "Edit" button { my ($Temp); $Temp = keys %::g_InputHash; # reset the iterator for "each" last; } } if ($value eq $::g_sRemoveButtonLabel) { @Response = ConfirmRemove(); # display a "Confirm remove" window } else { @Response = EditItem(); # edit the specified cart item } ($Status, $Message, $sHTML, $sCartID) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML, $sCartID); } elsif ($::g_sCurrentPage eq "PRODUCT") # the call was made from a product page which means - add item to cart { @Response = OrderDetails($::FALSE); # prompt the customer for order details ($Status, $Message, $sHTML, $sCartID) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML, $sCartID); } elsif ($::g_sCurrentPage eq "ORDERDETAIL") # the call was made from the order detail page { if ($sAction eq $::g_sCancelButtonLabel) # Cancel the add { @Response = ReturnToLastPage(0, "", ""); # bounce back in the broswer ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML); } else # Confirm the add (or confirm and checkout now) # elsif ($sAction eq "Confirm") no longer used since the user could hit to confirm or do a checkout now { if ($#::g_PageList == 1) # true when the adding an item to cart (only one page is the history list) { @Response = AddToCart(); # add the item to the cart ($Status, $Message, $sHTML, $sCartID) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML, $sCartID); # print the page and set the cookie } else # called by the shopping cart page - edit mode { @Response = ChangeCartItem(); # change the item in the cart ($Status, $Message, $sHTML, $sCartID) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } PrintPage($sHTML, $sCartID); # print the page and set the cookie } } } } ####################################################### # # SearchPages - search the HTML pages for the text # string specified by ::g_InputHash{'SEARCH_STRING'} # # Expects: %::g_InputHash, and %g_SetupBlob # should be defined # # Returns: ($ReturnCode, $Error, $sHTML, $sCartID) # if $ReturnCode = $FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the order detail page # $sCartID - the cart id # ####################################################### sub SearchPages { my ($sPath, @FileList, @Response, $Status, $Message); $sPath = $::g_InputHash{"PATH"}; # get the path to the web site dir my ($sLocalPage); $sLocalPage = pop @::g_PageList; # get the last item in the list push (@::g_PageList, $sLocalPage); # put the item back push (@::g_PageList, $sLocalPage); # dup the item (this allows us to bounce properly using ReturnToLastPage) my ($sSearchString, $sOriginalSearchString, $sHitHTML); $sSearchString = $::g_InputHash{'SEARCH_STRING'}; # read the search string if (length $sSearchString == 0) # if the search string is empty, bounce them back to the search page { return ($::FAILEDSEARCH, "" . ACTINIC::GetPhrase(-1, 41) . "", 0, 0); } $sOriginalSearchString = $sSearchString; # keep the untouched string around @Response = ACTINIC::ReadTheDir($sPath); # read the contents of the directory ($Status, $Message, @FileList) = @Response; # get a copy of the directory listing if ($Status != $::SUCCESS) { return(@Response); } my ($sFile, $sFilePath, $bFoundHit); $sHitHTML = "\n"; # # have the complete list of files that match now # # # print the status # ($Status, $sOriginalSearchString) = ACTINIC::EncodeText($sOriginalSearchString); # encode the search string if ($Status != $::SUCCESS) # so it is printable { return ($Status, $sSearchString, "", 0); } if (!$bFoundHit) # if no matches were found { return ($::FAILEDSEARCH, "" . ACTINIC::GetPhrase(-1, 42, $sOriginalSearchString) . "", 0, 0); } my ($sHTML); $sHTML = ACTINIC::GetPhrase(-1, 43, $sOriginalSearchString) . "

\n"; # # add the list of hits to the document # $sHTML .= $sHitHTML; my (%VariableTable); $VariableTable{$::VARPREFIX."SEARCHRESULTS"} = $sHTML; # add the body to the var list @Response = ACTINIC::TemplateFile($sPath."results.html", \%VariableTable); # make the substitutions ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } ####### # make the file references point to the correct directory ####### @Response = ACTINIC::MakeLinksAbsolute($sHTML, $::g_sWebSiteUrl, $::g_sContentUrl); ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } # # make CGI scripts refer back to the static search page # my $sURL = $::g_sWebSiteUrl . "search.html"; @Response = ACTINIC::EncodeText($sURL); $sURL = $Response[1]; $sHTML =~ s/(\<\s*A\s*HREF[^>?]+\?)/$1ACTINIC_REFERRER=$sURL&/gi; return ($::SUCCESS, "", $sHTML, 0); } ####################################################### # # ConfirmRemove - display a window to confirm that the # customer wants to remove the item from the cart # # Expects: %::g_InputHash, and %g_SetupBlob # should be defined # # Returns: ($ReturnCode, $Error, $sHTML, $sCartID) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the order detail page # $sCartID - the cart id # ####################################################### sub ConfirmRemove { no strict 'refs'; ###### # the name of the "Remove" button is the cart item number of interest ###### my ($bFound, $key, $value, $nItemIndex); $bFound = $::FALSE; while (($key, $value) = each %::g_InputHash) # locate the "Remove" button { if ($value =~ /$::g_sRemoveButtonLabel/) # found the "Remove" button { $bFound = $::TRUE; my ($Temp); $Temp = keys %::g_InputHash; # reset the iterator for "each" $Temp = $Temp; # removed compiler warning $nItemIndex = $key; last; } } my (%VariableTable, $sLine); $sLine = "\n"; $VariableTable{$::VARPREFIX."PAGE"} = $sLine; # add the page name my (@Response, $Status, $Message, $sCartID, $pCartList); @Response = ActinicOrder::GetCartID($::g_InputHash{"PATH"}); # retrieve the cart ID ($Status, $Message, $sCartID) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } @Response = ActinicOrder::ReadCart($sCartID, $::g_InputHash{'PATH'}); # read the shopping cart ($Status, $Message, $pCartList) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } my (%CartItem); %CartItem = %{ $$pCartList[$nItemIndex] }; # retrieve the item of interest # # locate this product's object. # my ($pProduct); @Response = ACTINIC::GetProduct($CartItem{"PRODUCT_REFERENCE"}, $CartItem{SECTION_BLOB}, $::g_InputHash{'PATH'}); # get this product object ($Status, $Message, $pProduct) = @Response; if ($Status == $::NOTFOUND) # the item has been removed from the catalog { # no-op, deleted product works fine here } if ($Status == $::FAILURE) { return (@Response); } # product description my ($sDescription, $sProdRef); @Response = ACTINIC::ProcessEscapableText($$pProduct{"NAME"});# get the product name ($Status, $sDescription) = @Response; # format the product name for HTML if ($Status != $::SUCCESS) { return (@Response); } # product reference (optional) @Response = FormatProductReference($CartItem{"PRODUCT_REFERENCE"}); ($Status, $Message, $sProdRef) = @Response; if ($Status != $::SUCCESS) { return (@Response); } # Quantity my ($sFormat, $sQuantity); # # Use prompt field for formating # $sFormat = ACTINIC::GetPhrase(-1, 166) . ' %d'; $sQuantity = sprintf($sFormat, $CartItem{"QUANTITY"}); # price per item my ($sPrice); @Response = FormatCompletePrice($$pProduct{"PRICE"}, $$pProduct{"TAX_TREATMENT"}); ($Status, $Message, $sPrice) = @Response; if ($Status != $::SUCCESS) { return (@Response); } if (length $sPrice > 0) { $sPrice .= "
"; } # total my ($nTotal, $sTotal); $nTotal = $CartItem{"QUANTITY"} * $$pProduct{"PRICE"}; # calculate the order detail total # # we want to label this line with Total (-1, 103) rather than price # @Response = FormatCompletePrice($nTotal, $$pProduct{"TAX_TREATMENT"}, 103); ($Status, $Message, $sTotal) = @Response; if ($Status != $::SUCCESS) { return (@Response); } $sTotal .= "
"; # optional date field my ($sDate); if (length $CartItem{"DATE"} > 0) # if there is any date info { $sDate = $$pProduct{"DATE_PROMPT"}; # build the prompt $sDate .= " "; $sDate .= $CartItem{"DATE"}; # plus the response $sDate .= "
"; } # optional info field my ($sInfo); if (length $CartItem{"INFOINPUT"} > 0) # if there is any info { $sInfo = $$pProduct{"OTHER_INFO_PROMPT"}; # build the prompt $sInfo .= " "; $sInfo .= $CartItem{"INFOINPUT"}; # plus the response $sInfo .= "
"; } # build block $sLine = sprintf('

%s%s

%s%s%s%s
%s

', $sDescription, $sProdRef, $sDate, $sInfo, $sPrice, $sQuantity, $sTotal); $sLine .= ACTINIC::GetPhrase(-1, 46) . "

\n"; # PRESNET # check if we want to display the Confirm button as an image # if (defined $$::g_pSetupBlob{'CONFIRM_IMG'} && $$::g_pSetupBlob{'CONFIRM_IMG'} ne '') { $sLine .= " \n"; } else { $sLine .= " \n"; } # # check if we want to display the Cancel button as an image # if (defined $$::g_pSetupBlob{'CANCEL_IMG'} && $$::g_pSetupBlob{'CANCEL_IMG'} ne '') { $sLine .= "

\n"; } else { $sLine .= "

\n"; } # PRESNET $sLine .= "\n"; $VariableTable{$::VARPREFIX."BODY"} = $sLine; # add the page name my ($sPath, $sHTML); $sPath = $::g_InputHash{"PATH"}; # get the path to the web site dir @Response = ACTINIC::TemplateFile($sPath."CRTemplate.html", \%VariableTable); # make the substitutions ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } ####### # make the file references point to the correct directory ####### @Response = ACTINIC::MakeLinksAbsolute($sHTML, $::g_sWebSiteUrl, $::g_sContentUrl); ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } return ($::SUCCESS, "", $sHTML, $sCartID); } ####################################################### # # ChangeCartItem - change the item in the cart # # Confirm that the data is valid. If so, add the item # to the cart. If not, redisplay the order details # page with a message explaining the problems. # # Expects: %::g_InputHash, and %g_SetupBlob # should be defined # # Returns: ($ReturnCode, $Error, $sHTML, $sCartID) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the order detail page # $sCartID - the cart id # ####################################################### sub ChangeCartItem { my ($Status, $Message, %OrderDetails, $nIndex, $sCartID, @Response); @Response = ActinicOrder::GetCartID($::g_InputHash{"PATH"}); # retrieve the cart ID ($Status, $Message, $sCartID) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } ($Status, $Message, %OrderDetails) = ValidateOrderDetails($::TRUE); # attempt to validate the data entered by the user $nIndex = $::g_InputHash{"ITEMINDEX"}; # get the cart index number for this item if ($Status == $::BADDATA) # the data was invalid { my ($sSearch, $sReplace); $sSearch = "\n" . " 0) # if there was any data in the date field { $nDay = substr($CartItem{"DATE"}, 8, 2); # retrieve the date components from the compiled date value $nMonth = substr($CartItem{"DATE"}, 5, 2); # which is in actinic internal format YYYY/MM/DD $nYear = substr($CartItem{"DATE"}, 0, 4); $nMonth = int $nMonth; # get rid of any leading zero $nDay = int $nDay; # get rid of any leading zero } my ($sHTML); @Response = OrderDetails($::TRUE, $nDay, $nMonth, $nYear); # rebuild the order detail page ($Status, $Message, $sHTML, $sCartID) = @Response; # read the response if ($Status != $::SUCCESS) # error out { return(@Response); } my ($sSearch, $sReplace); $sSearch = "\n" . " 0) # if there was any data in the info prompt { my ($sInfoValue); $sInfoValue = ACTINIC::EncodeText2($CartItem{"INFOINPUT"}); # retrieve the value $Variables{"NAME=INFOINPUT"} = "NAME=INFOINPUT VALUE=\"$sInfoValue\""; # make it the default for the next round } my ($nQuantity); $nQuantity = $CartItem{"QUANTITY"}; $Variables{"NAME=QUANTITY VALUE=\"\\d+\""} = # make the last quantity the default "NAME=QUANTITY VALUE=\"$nQuantity\""; # for the next round @Response = ACTINIC::TemplateString($sHTML, \%Variables); # make the substitutions ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } return ($::SUCCESS, "", $sHTML, $sCartID); # now display the order details } ####################################################### # # RemoveItem - remove the selected item from the cart # and redisplay the cart # # Expects: %::g_InputHash, and %g_SetupBlob # should be defined # # Returns: ($ReturnCode, $Error, $sHTML, $sCartID) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the order detail page # $sCartID - the cart id # ####################################################### sub RemoveItem { my ($sCartID, @Response, $Status, $Message, $nItemIndex); @Response = ActinicOrder::GetCartID($::g_InputHash{"PATH"}); # retrieve the cart ID ($Status, $Message, $sCartID) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } @Response = ActinicOrder::RemoveItemFromCart($sCartID, $::g_InputHash{"ITEMINDEX"}, $::g_InputHash{'PATH'}); # remove item from cart ($Status, $Message) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } @Response = ReturnToLastPage(0, "", ""); # bounce back in the broswer my ($sHTML); ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); exit; } return ($::SUCCESS, "", $sHTML, $sCartID); # now redisplay the cart } ####################################################### # # ShowCart - display the shopping cart # # Expects: %::g_InputHash, and %g_SetupBlob # should be defined # # Returns: ($ReturnCode, $Error, $sHTML, $sCartID) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the order detail page # $sCartID - the cart id # ####################################################### sub ShowCart { my ($sCartID, @Response, $Status, $Message); @Response = ActinicOrder::GetCartID($::g_InputHash{"PATH"}); # retrieve the cart ID ($Status, $Message, $sCartID) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } my ($pCartList); @Response = ActinicOrder::ReadCart($sCartID, $::g_InputHash{'PATH'}); # read the shopping cart ($Status, $Message, $pCartList) = @Response; if ($Status != $::SUCCESS && $Status != $::EOF) # error out { return (@Response); } my ($sLine, %VariableTable); ####### # add the page name to a hidden field in the HTML ####### $sLine = ""; # define the page type $VariableTable{$::VARPREFIX."PAGE"} = $sLine; # add the page type to the variable table # # add the shopping cart items # @Response = ActinicOrder::GenerateShoppingCartLines($pCartList, $::TRUE); if ($Response[0] != $::SUCCESS) { return (@Response); } my ($sBody) = $Response[2]; # # add "Back" link # my ($sBack, $sPrevPage, @sTemp); if(defined $$::g_pSetupBlob{'DISPLAY_CART_AFTER_CONFIRM'} && $$::g_pSetupBlob{'DISPLAY_CART_AFTER_CONFIRM'}) { $sPrevPage = ACTINIC::GetLastNonScript(\@::g_PageList); # get the last page visited } else { $sPrevPage = $::g_PageList[$#::g_PageList]; # get the last page visited } $sBack = "

" . ACTINIC::GetPhrase(-1, 47) . "

\n"; $sBody = $sBack . $sBody . $sBack; # build the complete body $VariableTable{$::VARPREFIX."BODY"} = $sBody; # add the body to the var list my ($sPath, $sHTML); $sPath = $::g_InputHash{"PATH"}; # get the path to the web site dir @Response = ACTINIC::TemplateFile($sPath."SCTemplate.html", \%VariableTable); # make the substitutions ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } ####### # make the file references point to the correct directory ####### @Response = ACTINIC::MakeLinksAbsolute($sHTML, $::g_sWebSiteUrl, $::g_sContentUrl); ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } # # update the checkout link to pass along the website URL # my ($sPageList) = join ('|||', @::g_PageList); my ($sTemp, $sEncodedRef) = ACTINIC::EncodeText($sPageList, $::FALSE); # do CGI encoding first ($sTemp, $sEncodedRef) = ACTINIC::EncodeText($sEncodedRef); # follow up with HTML encoding $sHTML =~ s/(\?ACTION=[^"]*)/$1&REFPAGE=$sEncodedRef/gi; return ($::SUCCESS, "", $sHTML, $sCartID); } ####################################################### # # AddToCart - add the item to the cart # # Confirm that the data is valid. If so, add the item # to the cart. If not, redisplay the order details # page with a message explaining the problems. # # Expects: %::g_InputHash, and %g_SetupBlob # should be defined # # Returns: ($ReturnCode, $Error, $sHTML, $sCartID) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the order detail page # $sCartID - the cart id # ####################################################### sub AddToCart { my ($Status, $Message, %OrderDetails, $sCartID, @Response); @Response = ActinicOrder::GetCartID($::g_InputHash{"PATH"}); # retrieve the cart ID ($Status, $Message, $sCartID) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } ($Status, $Message, %OrderDetails) = ValidateOrderDetails($::FALSE); # attempt to validate the data entered by the user if ($Status == $::BADDATA) # the data was invalid { return ($::SUCCESS, "", $Message, $sCartID); # but act like life was a ::SUCCESS - display the warning } elsif ($Status != $::SUCCESS) # error while validating the data { return($Status, $Message, "", 0); # return the error } my ($nInitLineCount); @Response = ActinicOrder::CountCartItems($sCartID, $::g_InputHash{'PATH'}); # count items in the cart before we add the new one ($Status, $Message, $nInitLineCount) = @Response; if ($Status == $::FAILURE) # error out { return (@Response); } ######### # if we are here, the data is valid, add the item to the cart ######### @Response = ActinicOrder::AddItemToCart($sCartID, $::g_InputHash{'PATH'}, \%OrderDetails); # add this data item to the cart ($Status, $Message) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } my ($nLineCount); @Response = ActinicOrder::CountCartItems($sCartID, $::g_InputHash{'PATH'}); # count the items in the cart ($Status, $Message, $nLineCount) = @Response; if ($Status == $::FAILURE) # error out { return (@Response); } if ($nLineCount != ($nInitLineCount + 1)) # make sure the line was added - this is done because the prints { # don't seem to return a ::FAILURE return ($::FAILURE, ACTINIC::GetPhrase(-1, 49), 0, 0); } my ($sPageTitle, $sStatusMessage); $sPageTitle = ''; if ($nLineCount > 1) # be pluritically correct { $sStatusMessage = ACTINIC::GetPhrase(-1, 50, $nLineCount); } else { $sStatusMessage = ACTINIC::GetPhrase(-1, 168); } my ($sHTML); $sPageTitle = ACTINIC::GetPhrase(-1, 51); # # Presnet: check if we want to display the shopping cart contents after confirmation # if (defined $$::g_pSetupBlob{'DISPLAY_CART_AFTER_CONFIRM'} && $$::g_pSetupBlob{'DISPLAY_CART_AFTER_CONFIRM'}) { # # Display the cart contents with links # @Response = DisplayCartWithLinks($sCartID, $sPageTitle); ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) # error out { return (@Response); } } elsif ($::g_InputHash{ACTION} eq ACTINIC::GetPhrase(-1, 184)) # checkout now - bounce to the ordering screen { # # append the original URL to the checkout URL so it can find the images, etc. # @Response = ACTINIC::EncodeText($::g_PageList[0], $::FALSE); my $sDestinationUrl = $::g_InputHash{CHECKOUTURL} . "&ACTINIC_REFERRER=" . $Response[1]; # # now post the message and forward the browser # @Response = ACTINIC::BounceToPageEnhanced(2, "" . $sStatusMessage . "", $sPageTitle, \@::g_PageList, $::g_sWebSiteUrl, $::g_sContentUrl, \%::g_pSetupBlob, $sDestinationUrl, \%::g_InputHash, $::TRUE); # bounce to the checkout screen in the broswer - NOTE that the last argument causes the browser to use javascript to clear the frames if necessary ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) # error out { return (@Response); } } else # standard confirmation { @Response = ReturnToLastPage(2, "" . $sStatusMessage . "", $sPageTitle); # bounce back in the broswer ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) # error out { return (@Response); } } return ($::SUCCESS, "", $sHTML, $sCartID); } ####################################################### # # ValidateOrderDetails - Validate the order details. # If they are valid, return ::SUCCESS. If any are # invalid, return ::BADDATA with a modified OrderDetails # page packed into $Error. Can also return ::FAILURE # on unrecoverable error. # # Params: 0 - edit flag - if true we are editing # the item. if false, we are adding it # for the first time # # Expects: %::g_InputHash, and %g_SetupBlob # should be defined # # Returns: 0 - $ReturnCode # 1 - $Error # 2 - $pData (a reference to the order details) # # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # else $ReturnCode = $::BADDATA then $Error contains # the order detail page HTML modified to # correct the order # else $::SUCCESS then $pData contains the data # the page # ####################################################### sub ValidateOrderDetails { #? ACTINIC::ASSERT($#_ == 0, "Invalid argument count in ValidateOrderDetails ($#_)", __LINE__, __FILE__); my ($bEditMode) = @_; my ($bInfoExists, $bDateExists, $key, $value, $sMessage, %Values); $bInfoExists = $::FALSE; $bDateExists = $::FALSE; $sMessage = ""; # # Validate the cookie exists # # # parse the cookie - look for the actinic cart my ($sCookie, $Status, $Message, @Response); $sCookie = ACTINIC::GetCookie(); # retrieve the actinic cart ID if (!defined $sCookie || # the cookie hasn't been set length $sCookie == 0) { # # Build the server date # my (@Date, $day, $month, $sCurrentTime); @Date = gmtime(time); # current time in gmt $day = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat')[$Date[6]]; $month = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec')[$Date[4]]; $sCurrentTime = sprintf("%s, %02d %s %04d %02d:%02d:%02d GMT", $day, $Date[3], $month, $Date[5]+1900, $Date[2], $Date[1], $Date[0]); my ($sHTML); $sMessage = ACTINIC::GetPhrase(-1, 52, $sCurrentTime) . "\n"; ($Status, $Message, $sHTML) = ReturnToLastPage(-1, $sMessage, ACTINIC::GetPhrase(-1, 53)); return ($::BADDATA, $sHTML, 0, 0); # bounce back in the broswer } # # Locate the product of interest # my ($ProductRef, $pProduct); $ProductRef = $::g_InputHash{"PRODREF"}; if (length $ProductRef == 0) # if the product reference was not found { return ($::FAILURE, ACTINIC::GetPhrase(-1, 54), 0, 0); } @Response = ACTINIC::GetProduct($ProductRef, $::g_InputHash{SECTION_BLOB}, $::g_InputHash{'PATH'}); # get this product object ($Status, $Message, $pProduct) = @Response; # # items deleted from the catalog should error out here - they can't be tolerated at this point # if ($Status != $::SUCCESS) { return (@Response); } $bInfoExists = (length $$pProduct{"OTHER_INFO_PROMPT"} != 0); # see if the info field exists. $bDateExists = (length $$pProduct{"DATE_PROMPT"} != 0); # see if the date field exists $Values{'PRODUCT_REFERENCE'} = $ProductRef; # store the product reference my ($sInfo); if ($bInfoExists) # if the info prompt exists, it must contain data { $sInfo = $::g_InputHash{"INFOINPUT"}; if (length $sInfo == 0) # if there is no info, reprompt { my ($sPrompt); $sPrompt = $$pProduct{"OTHER_INFO_PROMPT"}; $sMessage .= ACTINIC::GetPhrase(-1, 55, "$sPrompt") . "

\n"; } elsif (length $sInfo > 1000) { my ($sPrompt); $sPrompt = $$pProduct{"OTHER_INFO_PROMPT"}; $sMessage .= ACTINIC::GetPhrase(-1, 56, "$sPrompt") . "

\n"; } $Values{"INFOINPUT"} = $sInfo; } my ($nDay, $sMonth, $nMonth, $nYear, $bBad); $bBad = $::FALSE; if ($bDateExists) # if the date prompt exists, confirm that the date isn't wacky { $nDay = $::g_InputHash{"DAY"}; # get the day, $sMonth = $::g_InputHash{"MONTH"}; # month, $nYear = $::g_InputHash{"YEAR"}; # and year fields $nMonth = $::g_MonthMap{$sMonth}; # convert the month to a digit for later use ####### # NOTE: the UI limits the day input to 1-31, so there is no need to check the majority of the months ####### if ( ($sMonth eq $::g_InverseMonthMap{'4'} || # 30 day months (April, June, September, November) $sMonth eq $::g_InverseMonthMap{'6'} || $sMonth eq $::g_InverseMonthMap{'9'} || $sMonth eq $::g_InverseMonthMap{'11'}) && $nDay > 30) { $bBad = $::TRUE; } elsif ($sMonth eq $::g_InverseMonthMap{'2'}) # 28/29 day month { if ($nDay > 29) # if the day is more than 29 { $bBad = $::TRUE; # definitely a problem } elsif ($nDay == 29) # if the day is exactly 29 { if ($nYear % 400 == 0) # if this is the fourth century { # no-op, leap year is OK on years divisible by 400 } elsif ($nYear % 100 == 0) # if the is century 1-3 { $bBad = $::TRUE; # leap year is skipped on 3 out of the 4 century years } elsif ($nYear % 4 == 0) # this is not a century, but is divisble by 4 { # no-op, leap year OK } else # all other years, leap year bad { $bBad = $::TRUE; # leap year is skipped on 3 out of the 4 years } } else # 28 days or less { # no-op, OK } } my $sPrompt = $$pProduct{"DATE_PROMPT"}; # warn and reprompt if (length $nDay == 0 || # if any of the date fields are undefined length $sMonth == 0 || length $nYear == 0) { $sMessage .= ACTINIC::GetPhrase(-1, 57, "$sPrompt") . "

\n"; } elsif ($bBad) # an error was found { $sMessage .= ACTINIC::GetPhrase(-1, 58, "$sPrompt") . "

\n"; } $Values{"DATE"} = sprintf("%4.4d/%2.2d/%2.2d", $nYear, $nMonth, $nDay); # store the value } my ($nIndex); $nIndex = -1; if ($#::g_PageList != 1) # if this is validation for an "Edit" { # compensate for the value already stored in the cart $nIndex = $::g_InputHash{"ITEMINDEX"}; # get the cart index number for this item } my ($nQuantity, $nMaxQuantity, $nMinQuantity); $nMinQuantity = $$pProduct{"MIN_QUANTITY_ORDERABLE"}; # get the min quantity count. this is maintained on a per # order detail basis if ($nIndex == -1) # we are not editing an item, so get the max allowable { ($Status, $Message, $nMaxQuantity) = GetMaxRemains($ProductRef, $::g_InputHash{SECTION_BLOB}); # calculate the maximum quantity of this item that can be added to the cart } else # we are editing an item, so get the max allowable, but compensate for { # the fact that we are changing an item already in the cart ($Status, $Message, $nMaxQuantity) = GetMaxRemains($ProductRef, $::g_InputHash{SECTION_BLOB}, $nIndex); # calculate the maximum quantity of this item that can be added to the cart } if ($Status != $::SUCCESS) { return($Status, $Message, 0, 0); } $nQuantity = $::g_InputHash{"QUANTITY"}; # retrieve the quantity ordered $nQuantity =~ s/^\s//g; # strip any leading white space $nQuantity =~ s/\s$//g; # strip any trailing white space if ($nMaxQuantity == 0) # if there is no limit on the quantity count { $nMaxQuantity = 32767; # it is still limited by the size of the quantity container } if ($nMaxQuantity == -1) # sold out { $sMessage .= ACTINIC::GetPhrase(-1, 59) . "

\n"; } elsif ($nQuantity =~ /\D/ || # if there are any non-digits in the quantity $nQuantity < $nMinQuantity || # or the quantity is not >= min quantity ($nMaxQuantity != 0 && # or ( the quantity ordered is more than the quantity allowed) $nQuantity > $nMaxQuantity) ) { if ($nMaxQuantity > 1) { $sMessage .= ACTINIC::GetPhrase(-1, 60, $nMinQuantity, $nMaxQuantity) . "

\n"; } elsif ($nMaxQuantity == 1) { $sMessage .= ACTINIC::GetPhrase(-1, 61) . "

\n"; } elsif ($nMaxQuantity == 0) { $sMessage .= ACTINIC::GetPhrase(-1, 62, $nMinQuantity) . "

\n"; } } $Values{"QUANTITY"} = $nQuantity; # store the quantity $Values{SECTION_BLOB} = $::g_InputHash{SECTION_BLOB}; # store the section blob # # Validate the shipping and tax info if it exists # if ($$::g_pSetupBlob{'TAX_AND_SHIP_EARLY'}) { $sMessage .= ActinicOrder::ValidatePreliminaryInfo($::TRUE); $sMessage .= ActinicOrder::ValidateTax($::TRUE, $::FALSE); } if (length $sMessage > 0) # there was a problem with at least one of the fields { $sMessage = "" . "
$sMessage


"; my ($sHTML, $sCartID); @Response = OrderDetails($bEditMode, $nDay, $nMonth, $nYear); # rebuild the order detail page ($Status, $Message, $sHTML, $sCartID) = @Response; # read the response if ($Status != $::SUCCESS) # error out { return(@Response); } ######### # insert the old values for the default values ######### my (%Variables); if (length $Values{"INFOINPUT"} > 0) # if there was any data in the info prompt { my ($sInfoValue); $sInfoValue = $Values{"INFOINPUT"}; # retrieve the value $Variables{"NAME=INFOINPUT"} = "NAME=INFOINPUT VALUE=\"$sInfoValue\""; # make it the default for the next round } $Variables{"NAME=QUANTITY VALUE=\"\\d+\""} = # make the last quantity the default "NAME=QUANTITY VALUE=\"$nQuantity\""; # for the next round $Variables{"= 0, "Invalid argument count in OrderDetails ($#_)", __LINE__, __FILE__); my ($bEditMode, @Date) = @_; # get the edit mode and default date (if any) my ($sPath, $bStandAlonePage); $sPath = $::g_InputHash{"PATH"}; # get the path to the web site dir my ($sLine, %VariableTable); ####### # add the product reference to a hidden field in the HTML ####### my ($ProductRef, $key, $value); $ProductRef = $::g_InputHash{"PRODREF"}; if (length $ProductRef == 0) # if the product reference was not found { while (($key, $value) = each %::g_InputHash) # locate the product reference { if (length $::g_sAddToButtonLabel > 0 && $value =~ /$::g_sAddToButtonLabel/) # found the add to cart button { $ProductRef = $key; # store the product reference my ($Temp); $Temp = keys %::g_InputHash; # reset the iterator for "each" $Temp = $Temp; # remove compiler warning last; } # # If it was an Image button, we don't seem to get the "Add To" value # so we have to look for something that looks like a coordinate # This will simply be the button name followed by ".x" or ".y" # if ($key =~ /.+\.[xy]/) # Looks like an image co-ordinate { ($ProductRef) = $key =~ /(.+)\.[xy]/; # # George's magic for exiting the loop again # my ($Temp); $Temp = keys %::g_InputHash; # reset the iterator for "each" $Temp = $Temp; # remove compiler warning last; } } } if (!$ProductRef) # if the product reference was not found { return ($::FAILURE, ACTINIC::GetPhrase(-1, 54), 0, 0); } my ($sCartID, $Status, $Message, $nMaxQuantity, @Response); @Response = ActinicOrder::GetCartID($sPath); # retrieve the cart ID ($Status, $Message, $sCartID) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } if ($::g_sCurrentPage eq "PRODUCT") # if this is the first viewing of the OD page, { ($Status, $Message, $nMaxQuantity) = GetMaxRemains($ProductRef, $::g_InputHash{SECTION_BLOB}); # calculate the maximum quantity of this item that can be added to the cart if ($Status != $::SUCCESS) { return($Status, $Message, 0, 0); } if ($nMaxQuantity == -1) # if max quantity has been met (already sold out) { my ($sLocalPage, $sMessage); $sLocalPage = pop @::g_PageList; # get the last item in the list push (@::g_PageList, $sLocalPage); # put the item back push (@::g_PageList, $sLocalPage); # dup the item (this allows us to bounce properly using ReturnToLastPage) $sMessage .= "" . ACTINIC::GetPhrase(-1, 63) . ""; @Response = ReturnToLastPage(5, $sMessage, ACTINIC::GetPhrase(-1, 64)); return ($Response[0], $Response[1], $Response[2], $sCartID); } } # # Now locate this product's object. To do this, we must read the catalog blob # my ($pProduct); @Response = ACTINIC::GetProduct($ProductRef, $::g_InputHash{SECTION_BLOB}, $sPath); # get this product object ($Status, $Message, $pProduct) = @Response; # # products deleted from the catalog should not be tolerated at this point, so error out # if ($Status != $::SUCCESS) { return (@Response); } # # Process the optional ship and tax prompts # my (@DeleteDelimiters, @KeepDelimiters); my($sMessage, $pVarTable, $pDeleteDelimiters, $pKeepDelimiters); ($Status, $sMessage, $pVarTable, $pDeleteDelimiters, $pKeepDelimiters) = ActinicOrder::DisplayPreliminaryInfoPhase($::FALSE); # get the ship charge phase info if ($Status != $::SUCCESS) { return ($Status, $sMessage, $pVarTable, $pDeleteDelimiters, $pKeepDelimiters); } my (@Array1, @Array2); # append the shipping stuff to the rest of it @Array1 = %$pVarTable; @Array2 = %VariableTable; push (@Array1, @Array2); %VariableTable = @Array1; push (@DeleteDelimiters, @$pDeleteDelimiters); push (@KeepDelimiters, @$pKeepDelimiters); ($Status, $sMessage, $pVarTable, $pDeleteDelimiters, $pKeepDelimiters) = # get the tax phase info ActinicOrder::DisplayTaxPhase($::FALSE); if ($Status != $::SUCCESS) { return ($Status, $sMessage, $pVarTable, $pDeleteDelimiters, $pKeepDelimiters); } @Array1 = %$pVarTable; # append the tax stuff to the rest of it @Array2 = %VariableTable; push (@Array1, @Array2); %VariableTable = @Array1; push (@DeleteDelimiters, @$pDeleteDelimiters); push (@KeepDelimiters, @$pKeepDelimiters); ($pDeleteDelimiters, $pKeepDelimiters) = # get the information that tells us which prompts to remove ActinicOrder::ParseDelimiterStatus($::PRELIMINARYINFOPHASE); push (@DeleteDelimiters, @$pDeleteDelimiters); push (@KeepDelimiters, @$pKeepDelimiters); ($pDeleteDelimiters, $pKeepDelimiters) = # get the information that tells us which prompts to remove ActinicOrder::ParseDelimiterStatus($::TAXCHARGEPHASE); push (@DeleteDelimiters, @$pDeleteDelimiters); push (@KeepDelimiters, @$pKeepDelimiters); ####### # Now we have all of the information that we need to procede. Check to see if the max quantity count = # min quantity count. If so and there are no prompts, automatically add it to the cart with quantity = min. ####### my $nVarCount = keys %$pVarTable; if ($$pProduct{"MIN_QUANTITY_ORDERABLE"} == $$pProduct{"MAX_QUANTITY_ORDERABLE"} && # if the quantities are equal $$pProduct{"DATE_PROMPT"} eq "" && # and there is no date prompt $$pProduct{"OTHER_INFO_PROMPT"} eq "" && # and there is no other info prompt (!$$::g_pSetupBlob{TAX_AND_SHIP_EARLY} || # and either we are not taking tax and ship info early, or $nVarCount == 0)) # the tax and shipping phases are hidden { # # Create a bounce page the emulates the order detail page. To do this, build the CGI GET URL. # my ($sCgiUrl); $sCgiUrl = sprintf('%sca%6.6d%s', $$::g_pSetupBlob{'CGI_URL'}, $$::g_pSetupBlob{'CGI_ID'}, $$::g_pSetupBlob{'CGI_EXT'}); # the cgi scrip URL # # Now add the parameters # my ($sGet); $sGet = "?"; srand(); my ($Random) = rand(); $sGet .= "RANDOM=" . $Random; @Response = ACTINIC::EncodeText($sPath, $::FALSE); $sGet .= "&PATH=" . $Response[1]; $sGet .= "&PAGE=ORDERDETAIL"; @Response = ACTINIC::EncodeText(ACTINIC::GetReferrer(), $::FALSE); $sGet .= "&REFPAGE=" . $Response[1]; @Response = ACTINIC::EncodeText($$pProduct{'REFERENCE'}, $::FALSE); $sGet .= "&PRODREF=" . $Response[1]; $sGet .= "&QUANTITY=" . $$pProduct{"MIN_QUANTITY_ORDERABLE"}; $sGet .= "&SECTION_BLOB=" . $::g_InputHash{SECTION_BLOB}; $sGet .= "&ACTION=CONFIRM"; # # now generate the page # my ($sRefPage, $sHTML); $sRefPage = $sCgiUrl . $sGet; @Response = ACTINIC::BounceToPagePlain(0, undef, undef, \@::g_PageList, $::g_sWebSiteUrl, $::g_sContentUrl, $::g_pSetupBlob, $sRefPage, \%::g_InputHash); if ($Response[0] != $::SUCCESS) { return (@Response); } return ($::SUCCESS, "", $Response[2], $sCartID); # add the item to the cart } $sLine = ""; $sLine .= ""; $VariableTable{$::VARPREFIX."PRODUCTREF"} = $sLine; # add the product reference to the var table ####### # add the product name to the html ####### @Response = ACTINIC::ProcessEscapableText($$pProduct{"NAME"});# get the product name ($Status, $sLine) = @Response; # format the product name for HTML if ($Status != $::SUCCESS) { return (@Response); } $VariableTable{$::VARPREFIX."PRODUCTNAME"} = $sLine; # add the product name to the var table ####### # add the product reference to the html ####### @Response = FormatProductReference($ProductRef); ($Status, $Message, $sLine) = @Response; if ($Status != $::SUCCESS) { return (@Response); } $VariableTable{$::VARPREFIX."DISPLAYPRODUCTREF"} = $sLine; # add the product ref to the var table ####### # add the product price to the html ####### @Response = FormatCompletePrice($$pProduct{"PRICE"}, $$pProduct{"TAX_TREATMENT"}); ($Status, $Message, $sLine) = @Response; if ($Status != $::SUCCESS) { return (@Response); } $VariableTable{$::VARPREFIX."PRODUCTPRICE"} = $sLine; # add the product price to the var table ####### # add the quantity prompt. if the min=max, hard code the quantity. otherwise, offer the prompt ####### if ($$pProduct{"MIN_QUANTITY_ORDERABLE"} == $$pProduct{"MAX_QUANTITY_ORDERABLE"} ) # if the quantities are equal { $VariableTable{$::VARPREFIX."QUANTITY"} = $$pProduct{"MIN_QUANTITY_ORDERABLE"} . # hard code the quantity ""; } else # the user can specify { $VariableTable{$::VARPREFIX."QUANTITY"} = ""; } ####### # add the date prompt (if any) to the html ####### my ($sDatePrompt); $sDatePrompt = $$pProduct{"DATE_PROMPT"}; # get the prompt text $sLine = ""; if (length $sDatePrompt > 0) # if there is a date prompt, print the message and format the prompt { my (@TimeList); @TimeList = localtime(time); # get the time $sLine = "

".$sDatePrompt."
\n"; # add the prompt to the html $sLine .= "\n"; # close the list $sLine .= "\n"; # close the list $sLine .= "\n"; # close the list $sLine .= "
\n"; } $VariableTable{$::VARPREFIX."DATEINPUT"} = $sLine; # add the date prompt (if any) to the var table ####### # add the info prompt (if any) to the html ####### my ($sInfoPrompt); $sInfoPrompt = $$pProduct{"OTHER_INFO_PROMPT"}; $sLine = ""; if (length $sInfoPrompt > 0) # if there is an info prompt, print the message and format the prompt { $sLine = "

".$sInfoPrompt."
\n"; # add the prompt to the html $sLine .= "\n"; # add the text field to the list } $VariableTable{$::VARPREFIX."INFOINPUT"} = $sLine; # add the info prompt (if any) to the var table # # Presnet: we may not want to display the cart contents until the item has been added # if (defined $$::g_pSetupBlob{'SUPPRESS_CART_WITH_CONFIRM'} && $$::g_pSetupBlob{'SUPPRESS_CART_WITH_CONFIRM'}) { $VariableTable{$::VARPREFIX.'THEORDERDETAILS'} = ""; # don't display the cart contents } else { # # Now display a summary of the shopping cart # my ($pCartList, @EmptyArray); @Response = ActinicOrder::ReadCart($sCartID, $sPath); # read the shopping cart if ($Response[0] != $::SUCCESS) # general error { $pCartList = \@EmptyArray; } else { $pCartList = $Response[2]; } # # if the cart contains any items, display it. Otherwise, skip it # my $sOrderDetailHTML; if ($#{$pCartList} >= 0) { @Response = ActinicOrder::GenerateShoppingCartLines($pCartList); if ($Response[0] != $::SUCCESS) { return (@Response); } $sOrderDetailHTML = $Response[2]; } $VariableTable{$::VARPREFIX.'THEORDERDETAILS'} = $sOrderDetailHTML; # add the order lines to the reciept } ####### # customize the file ####### @Response = ACTINIC::TemplateFile($sPath."ODTemplate.html", \%VariableTable); # customize the file my ($sHTML); ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } ####### # make the file references point to the correct directory ####### @Response = ACTINIC::MakeLinksAbsolute($sHTML, $::g_sWebSiteUrl, $::g_sContentUrl); ($Status, $Message, $sHTML) = @Response; if ($Status != $::SUCCESS) { return (@Response); } # # remove unused form blocks # my ($sDelimiter); foreach $sDelimiter (@DeleteDelimiters) # for each delimited section that is to be deleted { $sHTML =~ s/$::DELPREFIX$sDelimiter(.*?)$::DELPREFIX$sDelimiter//gs; # delete it (/s removes the \n limitation of .) } # # remove unused delimiters # foreach $sDelimiter (@KeepDelimiters) # for each delimiter that is not used { $sHTML =~ s/$::DELPREFIX$sDelimiter//gs; # delete it } # # remove the checkout now button if we are in the edit screen # if ($bEditMode) { my $sCheckOutNow = ACTINIC::GetPhrase(-1, 184); $sHTML =~ s/]*?$sCheckOutNow[^>]*?>//i; } return ($::SUCCESS, "", $sHTML, $sCartID); } ############################################################################################################## # # Command Processing - End # ############################################################################################################## ############################################################################################################## # # Text Processing - Begin # ############################################################################################################## ####################################################### # # FormatProductReference - format the product reference # # Params: $_[0] - the product reference # # Returns: ($ReturnCode, $Error, $sFormattedText, 0) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # ####################################################### sub FormatProductReference { if (!defined $_[0]) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 12, 'FormatProductReference'), 0, 0); } my ($sProdRef, $sFormat, $sLine, @Response, $Status, $Message); $sProdRef = $_[0]; # retrieve the product ref from the argument list $sLine = ""; if ($$::g_pSetupBlob{"PROD_REF_COUNT"} > 0) # if the product ref is to be displayed { $sLine = ACTINIC::GetPhrase(-1, 65, $sProdRef); # format the message @Response = ACTINIC::EncodeText($sLine); # convert the special characters to their hex codes ($Status, $sLine) = @Response; if ($Status != $::SUCCESS) { return (@Response); } $sLine = "" . $sLine . ""; } return ($::SUCCESS, "", $sLine, 0); } ####################################################### # # FormatCompletePrice - format the price with the tax # message into a text string including the HTML # and lables # # Params: $_[0] - the price in catalog format # $_[1] - the tax treatment # $_[2] - prompt id for label (optional) # # Returns: ($ReturnCode, $Error, $sFormattedText, 0) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # ####################################################### sub FormatCompletePrice { if (!defined $_[0] || !defined$_[1]) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 12, 'FormatCompletePrice'), 0, 0); } my $nLabelPrompt = $_[2]; my ($sLine, $nPrice, $eTaxTreatment, $Status, $Message, @Response); $sLine = ""; $nPrice = $_[0]; $eTaxTreatment = $_[1]; if ($$::g_pSetupBlob{"PRICES_DISPLAYED"} && # if the prices can be displayed $nPrice != 0) # and the item is not free { my ($sPrice); @Response = ActinicOrder::FormatPrice($nPrice, $::TRUE, $::g_pCatalogBlob); # format the price ($Status, $Message, $sPrice) = @Response; if ($Status != $::SUCCESS) { return (@Response); } @Response = ACTINIC::EncodeText($sPrice, $::TRUE, $::TRUE); # convert special characters to their hex equivalent ($Status, $sPrice) = @Response; if ($Status != $::SUCCESS) { return (@Response); } my ($sExcludes); @Response = FormatTaxMessage($eTaxTreatment); # get the tax treatment ($Status, $Message, $sExcludes) = @Response; # build the "Excludes Tax" message if ($Status != $::SUCCESS) { return (@Response); } @Response = ACTINIC::EncodeText($sExcludes); # convert special characters to their hex equivalent ($Status, $sExcludes) = @Response; if ($Status != $::SUCCESS) { return (@Response); } # # get the prompt label if one is specified # or the price prompt if none specified # my $sLabel; if (defined $nLabelPrompt) { $sLabel = ACTINIC::GetPhrase(-1, $nLabelPrompt); } else { $sLabel = ACTINIC::GetPhrase(-1, 66); } $sLine = $sLabel . ": " . $sPrice . " " . $sExcludes . ""; # generate the price html } return ($::SUCCESS, "", $sLine, 0); } ####################################################### # # FormatTaxMessage - format the tax exclusion message # into a text string # # Params: $_[0] - the tax treatment # # Returns: ($ReturnCode, $Error, $sFormattedText, 0) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # ####################################################### sub FormatTaxMessage { if (!defined $_[0]) { return ($::FAILURE, ACTINIC::GetPhrase(-1, 12, 'FormatTaxMessage'), 0, 0); } my ($sExcludingMessage, $eTaxTreatment, $sFormat, $sTax1, $sTax2); $eTaxTreatment = $_[0]; # tax status $sExcludingMessage = ""; $sTax1 = $$::g_pSetupBlob{"TAX_1_DESCRIPTION"}; # tax 1 description $sTax2 = $$::g_pSetupBlob{"TAX_2_DESCRIPTION"}; # tax 2 description if ($eTaxTreatment == 2) # tax one { $sExcludingMessage = ACTINIC::GetPhrase(-1, 67, $sTax1); } elsif ($eTaxTreatment == 3) # tax two { $sExcludingMessage = ACTINIC::GetPhrase(-1, 67, $sTax2); } elsif ($eTaxTreatment == 4) # both taxes { my ($sCombined); $sCombined = ACTINIC::GetPhrase(-1, 68, $sTax1, $sTax2); $sExcludingMessage = ACTINIC::GetPhrase(-1, 67, $sCombined); } return ($::SUCCESS, "", $sExcludingMessage, 0); } ############################################################################################################## # # Text Processing - End # ############################################################################################################## ############################################################################################################## # # Initialization and Input - Begin # ############################################################################################################## ####################################################### # # Init - initialize the script # ####################################################### sub Init { $::prog_name = "SHOPCART"; # Program Name $::prog_name = $::prog_name; $::prog_ver = '$Revision: 129 $ '; # program version $::prog_ver = substr($::prog_ver, 11); # strip the revision information $::prog_ver =~ s/ \$//; # and the trailers my (@Response, $Status, $Message); @Response = ReadAndParseInput(); # read the input from the CGI call ($Status, $Message) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); } @Response = ReadAndParseBlobs(); # read the catalog blobs ($Status, $Message) = @Response; # parse the response if ($Status != $::SUCCESS) { ACTINIC::ReportError($Message, $::g_InputHash{'PATH'}); } # # read the prompt blob # @Response = ACTINIC::ReadPromptFile($::g_InputHash{'PATH'}); if ($Response[0] != $::SUCCESS) { ACTINIC::ReportError($Response[1], $::g_InputHash{'PATH'}); } # # initialize some global hashes (must come after prompt file) # ACTINIC::InitMonthMap(); # PRESNET # # initialize some Presnet hashes (must come after prompt file) # if(!defined $::g_InputHash{"ACTION"}) { if(defined $::g_InputHash{"ACTION_CONFIRM.x"}) { $::g_InputHash{"ACTION"} = $::g_sConfirmButtonLabel; } elsif(defined $::g_InputHash{"ACTION_CANCEL.x"}) { $::g_InputHash{"ACTION"} = $::g_sCancelButtonLabel; } elsif(defined $::g_InputHash{"ACTION_BUYNOW.x"}) { $::g_InputHash{"ACTION"} = ACTINIC::GetPhrase(-1, 184); } elsif (defined $$::g_pSetupBlob{'EDIT_IMG'} && $$::g_pSetupBlob{'EDIT_IMG'} ne '') { my $sKey; foreach $sKey (keys(%::g_InputHash)) { if ($sKey =~ /^ACTION_EDIT(\d+)\.x/) { $::g_InputHash{$1} = $::g_sEditButtonLabel; } elsif ($sKey =~ /^ACTION_REMOVE(\d+)\.x/) { $::g_InputHash{$1} = $::g_sRemoveButtonLabel; } } } } # PRESNET } ####################################################### # # ReadAndParseInput - read the input and parse it # # Expects: $ENV to be defined # # Affects: @::g_PageList - global list of pages visited # # Returns: ($ReturnCode, $Error) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # ####################################################### sub ReadAndParseInput { my ($status, $message, $temp); ($status, $message, $::g_OriginalInputData, $temp, %::g_InputHash) = ACTINIC::ReadAndParseInput(); if ($status != $::SUCCESS) { return ($status, $message, 0, 0); } # # parse the ref page list # ($status, $message, @::g_PageList) = ACTINIC::ProcessReferencePageData(%::g_InputHash); if ($status != $::SUCCESS) { return ($status, $message, 0, 0); } ####### # retrieve the web site url ####### ($status, $message, $::g_sWebSiteUrl, $::g_sContentUrl) = ACTINIC::GetWebSiteURL(@::g_PageList); if ($status != $::SUCCESS) { return ($status, $message, 0, 0); } return ($::SUCCESS, "", 0, 0); } ####################################################### # # ReadAndParseBlobs - read the blobs and store them # in global data structures # # Expects: %::g_InputHash - the input hash table should # be defined # # Affects: %::g_BillContact - the invoice contact info # %::g_ShipContact - the delivery contact info # %::g_ShipInfo - the shipping info # %::g_TaxInfo - the tax exemption info # %::g_GeneralInfo - the general info page info # %g_PaymentInfo - the payment details # # Returns: ($ReturnCode, $Error) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # ####################################################### sub ReadAndParseBlobs { my ($Status, $Message, @Response, $sPath); $sPath = $::g_InputHash{"PATH"}; # get the path to the web site @Response = ACTINIC::ReadCatalogFile($sPath); # read the catalog blob ($Status, $Message) = @Response; # parse the response if ($Status != $::SUCCESS) # on error, bail { return (@Response); } @Response = ACTINIC::ReadSetupFile($sPath); # read the setup ($Status, $Message) = @Response; if ($Status != $::SUCCESS) { return (@Response); } # # read the cart ID # my ($sCartId); @Response = ActinicOrder::GetCartID($::g_InputHash{"PATH"}); # retrieve the cart ID ($Status, $Message, $sCartId) = @Response; if ($Status != $::SUCCESS) # error out { return (@Response); } # # read the checkout status # my ($pBillContact, $pShipContact, $pShipInfo, $pTaxInfo, $pGeneralInfo, $pPaymentInfo); @Response = ActinicOrder::RetrieveCheckoutStatus($sPath, $sCartId); if ($Response[0] != $::SUCCESS) { return (@Response); } ($Status, $Message, $pBillContact, $pShipContact, $pShipInfo, $pTaxInfo, $pGeneralInfo, $pPaymentInfo) = @Response; %::g_BillContact = %$pBillContact; # copy the hashes to global tables %::g_ShipContact = %$pShipContact; %::g_ShipInfo = %$pShipInfo; %::g_TaxInfo = %$pTaxInfo; %::g_GeneralInfo = %$pGeneralInfo; %::g_PaymentInfo = %$pPaymentInfo; return ($::SUCCESS, ""); } ############################################################################################################## # # Initialization and Input - End # ############################################################################################################## ############################################################################################################## # # Output - Begin # ############################################################################################################## ####################################################### # # ReturnToLastPage - bounce the browser to the previous # page. NOTE: this is a wrapper for the ACTINIC # package version. It prevents a bunch of duplicate # work # # Params: [0] - bounce delay # [1] - string to add to display # [2] - optional page title. If the page # title exists, the page is formatted # using the bounce template # # Expects: %::g_InputHash should be defined # # Returns: ($ReturnCode, $Error, $sHTML, 0) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the bounce page # ####################################################### sub ReturnToLastPage { my ($nDelay, $sMessage, $sTitle); ($nDelay, $sMessage, $sTitle) = @_; if (!defined $sTitle) { $sTitle = ""; } return (ACTINIC::ReturnToLastPage($nDelay, $sMessage, $sTitle, \@::g_PageList, $::g_sWebSiteUrl, $::g_sContentUrl, $::g_pSetupBlob, %::g_InputHash)); } ####################################################### # # GroomHTML - Display HTML with header/footer and background # NOTE: this is a wrapper for the ACTINIC # package version. It prevents a bunch of duplicate # work (Presnet). # # Params: [0] - string to add to display # [1] - optional page title. If the page # title exists, the page is formatted # using the bounce template # # Expects: %::g_InputHash should be defined # # Returns: ($ReturnCode, $Error, $sHTML, 0) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the page # ####################################################### sub GroomHTML { my ($sMessage, $sTitle); ($sMessage, $sTitle) = @_; if (!defined $sTitle) { $sTitle = ""; } return (ACTINIC::GroomHTML($sMessage, $sTitle, \@::g_PageList, $::g_sWebSiteUrl, $::g_sContentUrl, $::g_pSetupBlob, %::g_InputHash)); } ####################################################### # # PrintPage - Print the HTML to the browser. NOTE: # this is just a wrapper for the ACTINIC package # function. # # Params: [0] - HTML # [1] - Cookie (optional) # [2] - cache flag (optional - default no-cache) # ####################################################### sub PrintPage { return ( ACTINIC::UpdateDisplay($_[0], $::g_OriginalInputData, \@::g_PageList, $_[1], $_[2]) ); } ####################################################### # # AddLink - Formats the HTML for a link (Presnet) # # Params: [0] - URL # [1] - Text # # Expects: %::g_InputHash should be defined # # Returns: ($ReturnCode, $Error, $sHTML, 0) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the link # ####################################################### sub AddLink { my ($sURL, $sTarget, $sImage, $sAlt, $sText) = @_; my ($sHTML); # # add the opening tag # $sHTML .= ""; # # add the image # if (defined $sImage && $sImage ne '' && ACTINIC::CheckFileExists($sImage, $::g_InputHash{"PATH"})) { $sHTML .= "\""
"; } # # add the text label # $sHTML .= "" . $sText . "

"; return($::SUCCESS, "", $sHTML); } ####################################################### # # DisplayCartWithLinks - Gets the HTML for displaying # the cart contents with links to continue shopping # and going to checkout (Presnet). # # Params: [0] - Cart ID # [1] - Page Title # # Expects: %::g_InputHash should be defined # # Returns: ($ReturnCode, $Error, $sHTML, 0) # if $ReturnCode = $::FAILURE, the operation failed # for the reason specified in $Error # Otherwise everything is OK # $sHTML - the HTML of the link # ####################################################### sub DisplayCartWithLinks { # # Now display a summary of the shopping cart # my ($sCartID, $sPageTitle, $pCartList, @EmptyArray, $sStartButton); my ($Status, $Message, $sHTML, @Response); ($sCartID, $sPageTitle) = @_; @Response = ActinicOrder::ReadCart($sCartID, $::g_InputHash{'PATH'}); # read the shopping cart if ($Response[0] != $::SUCCESS) # general error { $pCartList = \@EmptyArray; } else { $pCartList = $Response[2]; } @Response = ActinicOrder::GenerateShoppingCartLines($pCartList); if ($Response[0] != $::SUCCESS) { return (@Response); } $sHTML .= $Response[2]; # # we want to get the refering page ignoring the previous script call # my ($sRefPage, $sPathArg, $sRefPageArg); # # save the confirmation script call # $sRefPage = $::g_PageList[-2]; # # Add the path to catalog. # @Response = ACTINIC::EncodeText($::g_InputHash{'PATH'}, $::FALSE); $sPathArg = "&PATH=" . $Response[1]; # # use the section page for use as the referer # @Response = ACTINIC::EncodeText($sRefPage, $::FALSE); $sRefPageArg .= "&REFPAGE=" . $Response[1]; # # set up a table with the links # $sHTML .= "
"; $sHTML .= "
"; # # add the continue shopping link to the HTML # my ($sLinkHTML, $sTarget); ($Status, $Message, $sLinkHTML) = AddLink($sRefPage, "_self", $$::g_pSetupBlob{'CONTINUE_SHOP'}, "Continue Shopping", ""); # parse the response if ($Status != $::SUCCESS) # error out { return (@Response); } $sHTML .= $sLinkHTML; # add to page # # add table divider # $sHTML .= ""; # # add the edit cart link to the HTML # # # Build the cart script URL. # my $sCartURL = sprintf('%sca%6.6d%s', $$::g_pSetupBlob{'CGI_URL'}, $$::g_pSetupBlob{'CGI_ID'}, $$::g_pSetupBlob{'CGI_EXT'}); # the cart script URL $sCartURL .= "?ACTION=SHOWCART" . $sPathArg . $sRefPageArg; ($Status, $Message, $sLinkHTML) = AddLink($sCartURL, "_self", $$::g_pSetupBlob{'EDIT_CART'}, "Show Cart", ""); # parse the response if ($Status != $::SUCCESS) # error out { return (@Response); } $sHTML .= $sLinkHTML; # add to page # # add table divider # $sHTML .= ""; # # build the link for proceed to checkout # my ($sCheckoutUrl); # # Build the order script URL. # $sCheckoutUrl = sprintf('%sos%6.6d%s', $$::g_pSetupBlob{'CGI_URL'}, $$::g_pSetupBlob{'CGI_ID'}, $$::g_pSetupBlob{'CGI_EXT'}); # the cgi script URL # # Add the arguments. # $sCheckoutUrl .= "?"; $sStartButton = ACTINIC::GetPhrase(-1, 113); @Response = ACTINIC::EncodeText($sStartButton, $::FALSE); $sCheckoutUrl .= "ACTION=" . $Response[1]; # add the action # # Add the path to catalog and refpage. # $sCheckoutUrl .= $sPathArg; # # if catalog is framed the target should be the parent frame # if (ACTINIC::IsCatalogFramed()) { $sTarget = "_parent"; # # to ensure we restore the frame we substitute the referring page # with the FRAMESET page # @Response = ACTINIC::GetCatalogBasePageName($::g_InputHash{'PATH'}); if($Response[0] != $::SUCCESS) # if we failed to get the page name { $sCheckoutUrl .= $sRefPageArg; # use the section page and live with the bug } else # we got the base page name { # # make the reference page absolute if required # my $sAbsBasePageURL = ($Response[2] =~ m#http.*://#) ? $Response[2] : $::g_sWebSiteUrl . $Response[2]; # # add the encoded argument to the URL as the REF page # @Response = ACTINIC::EncodeText($sAbsBasePageURL, $::FALSE); $sCheckoutUrl .= "&REFPAGE=" . $Response[1]; } } else { $sTarget = "_self"; # # Add the path to refpage. # $sCheckoutUrl .= $sRefPageArg; } # # format the link # ($Status, $Message, $sLinkHTML) = AddLink($sCheckoutUrl, $sTarget, $$::g_pSetupBlob{'PROCEED_CHECKOUT'}, "Proceed to Checkout", ""); # parse the response if ($Status != $::SUCCESS) # error out { return (@Response); } $sHTML .= $sLinkHTML; # add to page $sHTML .= "
"; # add closing tags for table # # format the HTML as a catalog page # @Response = GroomHTML("" . $sHTML . "", $sPageTitle); # bounce back in the broswer ($Status, $Message, $sHTML) = @Response; # parse the response if ($Status != $::SUCCESS) # error out { return (@Response); } return($::SUCCESS, "", $sHTML); } ############################################################################################################## # # Output - End # ##############################################################################################################