[ic] Multi page checkout example

Paul Jordan interchange-users@icdevgroup.org
Sun Jul 7 22:35:02 2002


After a couple requests of a multi page checkout tutorial, I promised to
make one. However, I am the last person who should be making a tutorial :)
So maybe this is just an example.  I don't offer any support, because I
barely know what is going on with it in the first place.


I modeled my checkout after buy.com. My site requires user registration for
a purchase. Please follow one rule.

1. if you want to see this site PLEASE USE my dev site at
http://www.imagemogul.com/cgi-bin/dev/index.html so I won't end up with alot
of erroneous "customers" in my real database. Not that anyone on this list
is erroneous :)

The database is empty, but if you click on "See" then type the word "image"
into the search engine... you will have some options. Or click "Listen" then
the sub category "Opera", or type the word opera into the search engine.


OK. I built my site around foundation (IC)4.8.3. I have 6 pages altogether
including my basket.html for the checkout scheme.


basket.html
		a page that, if it has items, will display a "checkout" button.
		Clicking this button will send the user to 'checkarea.html'


checkarea.html
		If the user is already logged_in, a bounce will send them to
		promoarea.html.

		If the user is not logged in, then checkarea.html is basically
		a login page. I combine my login and new account pages BTW. So
		if the user is already registered, they sign in, and go to
		promoarea.html.

		If they are not registered, they simply start the process on
		the same page under new account. After that, they are ported to
		editprofile.html.


editprofile.html
		This page is pretty much like account.html except after form submit,
		it sends the user to promoarea.html.

		This page utilizes the account_change profile in etc/profiles.order.


promoarea.html
		On this page I know two things, they are logged_in and their state.
		Thus I can already have my shipping calculated and ready to go.

		This page has a possible total of three payment option buttons.
			1. Online CC processing => checkout.html
			2. Offline CC or check, by mail/fax => checkout2.html
			3. Paypal

		In my store, if one of the items in the cart is a downloadable,
		then only option #1 appears. If there are no downloadables then
		all three options appear.

		Customer information cannot be edited at this point, however there
		is a little "edit" link next to their information.


checkout.html
		Online CC processing. One input present simply asking them to
		retype email address. Plus inputs for CC information.

		Customer information cannot be edited at this point, however there
		is a little "edit" link next to their information.

		Errors in the end submission will explain to click "edit" next to
		customer information and fix said mistakes.


checkout2.html
		Review order. Clicking on "next" will submit order (to IC) with
		the shipping status of HOLD.

		They are sent to receipt2.html which is a printable page that has
		their order details, and fields for them to manually fill in their
		CC#, or fold and mail with check.

		Has a different Order Route than checkout.


## Order Routes are configured inside of profiles.order

--
If anybody needs the actual pages zipped, I will send them offlist. I don't
want to make any bigger of an email than it has to be, for the gist ;) Send
requests for pages to paul@gishnetwork.com
--
###################OK -- Here are the basic form
elements:#####################

--------------------------------------
basket.html
--------------------------------------

	<FORM ACTION="[process-target secure=1]" METHOD=POST name="basket">
    	<INPUT TYPE=hidden NAME=mv_session_id VALUE="[data session id]">
    	<INPUT TYPE=hidden NAME=mv_doit VALUE=refresh>
    	<INPUT TYPE=hidden NAME=mv_orderpage VALUE="ord/basket">

[item-list]
....stuff here.....
[/item-list]


[button
     		  text="checkout"
	src="__BUTTON_DIR__/checkout.gif"
		  hidetext=1
		  form=basket
		  ]
			mv_todo=return
			mv_nextpage=ord/checkarea
		[/button]

</form>

--------------------------------------
checkarea.html
--------------------------------------

[if session logged_in][bounce href="[area ord/promoarea]"][else]

    [if session failure]
     [calc]delete $Session->{failure}[/calc]</area>
    [/if]

    <FORM ACTION="[process secure=1]" METHOD=POST>
    <input type=hidden name=mv_session_id value="[data session id]">
    <INPUT TYPE=hidden NAME=mv_click VALUE=Login>
    <INPUT TYPE=hidden NAME=mv_todo  VALUE=return>
    <INPUT TYPE=hidden NAME=mv_nextpage VALUE="ord/promoarea">

    [set Log In]
      mv_nextpage=@@MV_PAGE@@
    [/set]

	    <INPUT type="text" NAME=mv_username VALUE="[read-cookie MV_USERNAME]"
size=12px>
	    <INPUT TYPE=password NAME=mv_password VALUE="" size=12px>
	    <input type="hidden" NAME="mv_check" value="Log In">
	    <input type=image src="__BUTTON_DIR__/login2.gif" border="0" value="Log
In">
    </form>

[if !scratch new]

   [if session failure]
      [data session failure]
     [data base=session field=failure value=""]
   [/if]
[else]
    [set new][/set]
[/else]
[/if]

[set NewAccount]
  [if type=explicit compare="[userdb new_account]"]
     mv_nextpage=ord/editprofile
  [else]
     mv_nextpage=ord/checkarea
  [/else]
  [/if]
[/set]

<FORM ACTION="[process-target]" METHOD=POST>
<input type=hidden name=mv_session_id value="[data session id]">
<INPUT TYPE=hidden NAME=mv_click VALUE=NewAccount>
<INPUT TYPE=hidden NAME=mv_doit  VALUE=return>
<INPUT TYPE=hidden NAME=function  VALUE=new_account>

        <input type="text" NAME=mv_username VALUE=""> (no spaces)
        <INPUT TYPE=password NAME=mv_password VALUE="">
        <INPUT TYPE=password NAME=mv_verify VALUE="">
        <INPUT TYPE=image src="__BUTTON_DIR__/create.gif" border="0"
VALUE="Create Account">

</form>
[/else]
[/if]

--------------------------------------
promoarea.html
--------------------------------------

[if !session logged_in][bounce href="[area ord/checkarea]"][else]

   [if !items][bounce href="[area ord/basket]"][/if]

  [set mv_no_cache]1[/set]
  [set downloadable_present][/set]

    <FORM ACTION="[process secure=1]" METHOD=POST name=promo>
    <input type=hidden name=mv_session_id value="[data session id]">
    <INPUT TYPE=hidden NAME=mv_doit VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_nextpage VALUE=ord/promoarea>


[item-list]
....more code here....
[/item-list]

Customer Information: [page ord/editprofile]edit[/page]<br>
[value company]
[value fname] [value lname]
[value address1]
[if value address2][value address2][/if]
[value city] [value state], [value country]
[value phone_day]
....................................
[if value b_fname]
Shipping Address:
[value b_fname] [value b_lname]
[value b_address1]
[value b_address2]
[value b_city] [value b_state], [value b_country]
Orders shipped to different addresses may be delayed for verification.
....................................
[/if]


      [button
     		  text="recalc"
		  src="__BUTTON_DIR__/recalc.gif"
		  hidetext=1
		  form=promo
		  ]
			mv_orderpage=ord/promoarea
      [/button]


<SELECT NAME=mv_shipmode>
[shipping label=1 mode=|[data table=country key='[value country]'
col=shipmodes]|]
</SELECT>


Secure Online Payment:
MasterCharge, Visa, American Express

[button
     	text="secure online"
	src="__BUTTON_DIR__/arrow.gif"
	hidetext=1
	form=promo
	]
	  mv_nextpage=ord/checkout
[/button]


[if scratch downloadable_present == 1]
</form>
[else]


Mail / Fax Payment:
MasterCharge, Visa, American Express
Money Order or Check

[button
     	text="offline"
	src="__BUTTON_DIR__/arrow.gif"
	hidetext=1
	form=promo
	]
	  mv_nextpage=ord/checkout2
[/button]
</form>

Or, you can pay with Paypal:

<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="orders@imagemogul.com">
<input type="hidden" name="item_name" value="[item-list][item-modifier
title],[/item-list]">
<input type="hidden" name="item_number"
value="[item-list][item-sku],[/item-list]">
<input type="hidden" name="amount" value="[subtotal]">
<input type="image" src="__BUTTON_DIR__/paypal.gif" border="0"
name="submit">
</form>
[/else][/if]


[/else][/if]


--------------------------------------
checkout.html
--------------------------------------

[if !session logged_in][bounce href="[area ord/checkarea]"][else]

<FORM ACTION="[process secure=1]" METHOD="POST" name=checkout>
<INPUT TYPE=hidden NAME=mv_session_id VALUE="[data session id]">
<INPUT TYPE=hidden NAME=mv_doit VALUE=refresh>
<INPUT TYPE=hidden NAME=mv_nextpage VALUE="ord/checkout">

[if type=explicit compare="[error all=1 show_var=1 keep=1]"]
  There were errors in your last submission:
	<blockquote>
	<FONT color="__CONTRAST__">
		[error all=1 keep=1 show_error=1 show_label=1 joiner="<br>"]
	</blockquote>
	<p>

 	  	[error name=fname required=1]
	   	[error name=lname required=1]
	   	[error name=address1 required=1]
	  	[error name=city required=1]
	 	[error name=state required=1]
	  	[error name=zip required=1]
	  	[error name=email required=1]
                [error name=email2 required=1]
         	[error name=country required=1]
		[error name=phone_day required=1]
</p>
    [/if]


 <!--- credit card information --->

[error std_label="Credit Card Information" name=mv_credit_card_valid]

      <INPUT TYPE="hidden" NAME="payment_method" value="credit">
      <input type=hidden name=mv_order_profile value=credit_card>

	  [calc]
		my $accepted = $Variable->{CREDIT_CARDS_ACCEPTED};
		my (@out);
		my (@cc);
		my $out;
		push @cc, 'visa' if $accepted =~ /visa/;
		push @cc, 'mc' if $accepted =~ /mc/;
		push @cc, 'disc' if $accepted =~ /discover/;
		push @cc, 'amex' if $accepted =~ /amex/;
		for (@cc) {
		  push @out, qq{<IMG SRC="/im/images/small$_.png">};
		}
		return join '  ', @out;
	    [/calc]

             <INPUT TYPE=text NAME=mv_credit_card_number SIZE=22></b>

		<SELECT NAME=mv_credit_card_exp_month>
		[loop
			lr=1
		  	option=mv_credit_card_exp_month
			list="
1	01 - January
2	02 - February
3	03 - March
4	04 - April
5	05 - May
6	06 - June
7	07 - July
8	08 - August
9	09 - September
10	10 - October
11	11 - November
12	12 - December"]
		<OPTION VALUE="[loop-code]"> [loop-pos 1]
		[/loop]
		</SELECT>

		<SELECT NAME=mv_credit_card_exp_year>
		[comment]
		This should always return the current year as the first, then
		7 more years.
		[/comment]
		[loop option=mv_credit_card_exp_year lr=1 list=`
		my $year = $Tag->time( '', { format => '%Y' }, '%Y' );
		my $out = '';
		for ($year .. $year + 7) {
			/\d\d(\d\d)/;
			$last_two = $1;
			$out .= "$last_two\t$_\n";
		}
		return $out;
		`]

		<OPTION VALUE="[loop-code]"> [loop-pos 1]
		[/loop]
		</SELECT>

   	[button
		name="mv_click"
		src="__BUTTON_DIR__/placeorder.gif"
		text="Place Order"
		hidetext=1
		form=checkout
	]
		mv_todo=submit
	[/button]

      </form>

  [seti clear_errors][error all=1 hide=1 comment="Clear errors"][/seti]

[/else][/if]


--------------------------------------
checkout2.html
--------------------------------------

[if !session logged_in][bounce href="[area ord/checkarea]"][else]

    <FORM ACTION="[process secure=1]" METHOD="POST" name=checkout2>
    <INPUT TYPE=hidden NAME=mv_session_id VALUE="[data session id]">

[if type=explicit compare="[error all=1 show_var=1 keep=1]"]
    	There were errors in your last submission:
	<blockquote>
	<FONT color="__CONTRAST__">
		[error all=1 keep=1 show_error=1 show_label=1 joiner="<br>"]

	</blockquote>
	<p>

 	  	[error name=fname required=1]
	   	[error name=lname required=1]
	   	[error name=address1 required=1]
	  	[error name=city required=1]
	 	[error name=state required=1]
	  	[error name=zip required=1]
	  	[error name=email required=1]
                [error name=email2 required=1]
         	[error name=country required=1]
		[error name=phone_day required=1]
</p></b>
    [/if]


   <INPUT TYPE=hidden NAME=mv_doit VALUE=refresh>
    <INPUT TYPE=hidden NAME=mv_nextpage VALUE="ord/checkout2">
     <INPUT TYPE=hidden NAME=mv_order_profile VALUE="checkout_profile">

[item-list]
     ...more code here...
[/item-list]


<input type="hidden" name="status" value="HOLD">
<INPUT TYPE="hidden" NAME=email_copy VALUE="1">

   	[button
		name="mv_click"
		text="Next"
		hidetext=1
                src="__BUTTON_DIR__/next.gif"
		form=checkout2
	]
		mv_todo=submit
	[/button]

      </form>

  [seti clear_errors][error all=1 hide=1 comment="Clear errors"][/seti]

[/else][/if]
--------------------------------------
profiles.order => checkout_profile
#notice order route
--------------------------------------

__NAME__                            checkout_profile
fname=required
lname=required
address1=required

city=required
country=required
[if value country =~ /^(US|CA)$/i]
        state=state_province
        zip=postcode
[/if]
&or phone_night=phone, phone_day=phone Must have day or evening phone number

&fatal = yes
email=required
email=email

&set = mv_payment Incomplete

[value name=mv_order_route set="log main_b copy_user" hide=1]

[if value fax_order == 1]
&set = mv_payment Check or Money Order (will call)


[elsif variable MV_PAYMENT_MODE]
[/elsif]

[elsif config CyberCash]
&fail=../special_pages/failed
&charge=[var CYBER_MODE]
[/elsif]

[elsif config CreditCardAuto]
[/elsif]

[else]
[/else]
[/if]

&final = yes
&setcheck=mv_email [value email]

__END__

--------------------------------------
profiles.order => credit_card
#notice order route
--------------------------------------


__NAME__                            credit_card
fname=required
lname=required
email=email
address1=required
city=required
country=required
[if value country =~ /^(US|CA)$/i]
        state=state_province
        zip=postcode
[/if]
&or phone_night=phone, phone_day=phone Must have day or evening phone number
email=email
[if type=value term=email2 op=ne compare="[value email]"]
&calc = delete $CGI->{email2}; 1;
email2=mandatory Email2 doesn't match email.[/if]

[value name=mv_order_route set="log main copy_user" hide=1]

&fatal = yes

&set = mv_payment Incomplete

[if variable MV_PAYMENT_MODE]
&credit_card=standard keep __CREDIT_CARDS_ACCEPTED__
&charge=[var MV_PAYMENT_MODE][cgi mv_payment_test]
&set=mv_payment Real-time Credit Card (%c -- [var MV_PAYMENT_MODE])
[else]
&credit_card=standard __CREDIT_CARDS_ACCEPTED__
&set=mv_payment Credit Card (%c)
[/else]
[/if]

&calc = $Values->{mv_payment} =~ s/\%c/$Values->{mv_credit_card_type}/g; 1;
&final = yes
&setcheck=mv_email [value email]

__END__

--------------------------------------
Order Routes
--------------------------------------

Route log  <<EOF
        empty        1
        encrypt      0
        increment    0
        report       etc/log_transaction
        supplant     0
        track        logs/log
EOF

Route copy_user  <<EOF
        empty        1
        error_ok     1
        encrypt      0
        increment    0
        report       etc/mail_receipt
        supplant     0
        track        logs/log
EOF

Route main  <<EOF
        attach            0
        credit_card       0
        default           1
        email             '__ORDERS_TO__'
        encrypt           0
        errors_to         '__ORDERS_TO__'
        pgp_cc_key        "__PGP_KEY__"
        pgp_key           "__PGP_KEY__"
        report            etc/report
        receipt           etc/receipt.html
        supplant          1
        master            1
        individual_track  orders
        track             logs/tracking.asc
EOF

Route main_b  <<EOF
        attach            0
        credit_card       0
        default           1
        email             '__ORDERS_TO__'
        encrypt           0
        errors_to         '__ORDERS_TO__'
        pgp_cc_key        "__PGP_KEY__"
        pgp_key           "__PGP_KEY__"
        report            etc/report
        receipt           etc/receipt2.html
        supplant          1
        master            1
        individual_track  orders
        track             logs/tracking.asc
EOF

### and comment out the default route in catalog.cfg.

---------------------------------------------------------------------------

END


Paul