+ +Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-2.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-2.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-2.tcl 23 Jun 2005 12:28:22 -0000 1.1 @@ -0,0 +1,192 @@ +ad_page_contract { + @param address_id a stored address + @param usca_p User session started or not + + @author + @creation-date + @author ported by Jerry Asher (jerry@theashergroup.com) + @author Bart Teeuwisse (bart.teeuwisse@thecodemill.biz) + @revision-date April 20002 + +} { + address_id:optional,naturalnum + usca_p:optional +} + +# ec_redirect_to_https_if_possible_and_necessary + +# We need them to be logged in + +set user_id [ad_verify_and_get_user_id] +if {$user_id == 0} { + set return_url "[ad_conn url]" + ad_returnredirect "/register?[export_url_vars return_url]" + ad_script_abort +} + +# User sessions: +# 1. get user_session_id from cookie +# 2. if user has no session (i.e. user_session_id=0), attempt to set it if it hasn't been +# attempted before +# 3. if it has been attempted before, give them message that we can't do shopping carts +# without cookies + +set user_session_id [ec_get_user_session_id] +ec_create_new_session_if_necessary [export_url_vars address_id] + +# Make sure they have an in_basket order, otherwise they've probably +# gotten here by pushing Back, so return them to index.tcl + +set success_p [db_0or1row get_order_id_and_order_owner " + select order_id, user_id as order_owner + from ec_orders + where user_session_id = :user_session_id + and order_state='in_basket' "] +if { ! $success_p } { + + # No rows came back, so they probably got here by pushing "Back", + # so just redirect them to index.tcl + + rp_internal_redirect index + ad_script_abort +} + +if { $order_owner != $user_id } { + + # make sure the order belongs to this user_id (why? because + # before this point there was no personal information associated + # with the order (so it was fine to go by user_session_id), but + # now there is, and we don't want someone messing with their + # user_session_id cookie and getting someone else's order) + + # If they get here, either they managed to skip past checkout.tcl, + # or they messed w/their user_session_id cookie; + ad_returnredirect [ec_securelink [ec_url]checkout.tcl] + ad_script_abort +} + +# Make sure there's something in their shopping cart, otherwise +# redirect them to their shopping cart which will tell them that it's +# empty. + +if { [db_string get_ec_item_count " + select count(*) + from ec_items + where order_id=:order_id"] == 0 } { + rp_internal_redirect shopping-cart + ad_script_abort +} + +# Either address_id should be a form variable, or it should already be +# in the database for this order + +# Make sure address_id, if it exists, belongs to them, otherwise +# they've probably gotten here by form surgery, in which case send +# them back to checkout.tcl if it is theirs, put it into the database +# for this order + +# If address_id doesn't exist, make sure there is an address for this +# order, otherwise they've probably gotten here via url surgery, so +# redirect them to checkout.tcl + +if { [info exists address_id] && ![empty_string_p $address_id] } { + set n_this_address_id_for_this_user [db_string get_an_address_id " + select count(*) + from ec_addresses + where address_id = :address_id + and user_id=:user_id"] + if {$n_this_address_id_for_this_user == 0} { + ad_returnredirect [ec_securelink [ec_url]checkout] + ad_script_abort + } + + # It checks out ok + + db_dml update_ec_order_address " + update ec_orders + set shipping_address = :address_id + where order_id = :order_id" +} else { + + set address_id [db_string get_address_id " + select shipping_address + from ec_orders + where order_id=:order_id" -default ""] + if { [empty_string_p $address_id] } { + + # No shipping address is needed if the order only consists of + # soft goods not requiring shipping. + + if {[db_0or1row shipping_avail " + select p.no_shipping_avail_p, count (*) + from ec_items i, ec_products p + where i.product_id = p.product_id + and p.no_shipping_avail_p = 'f' + and i.order_id = :order_id + group by no_shipping_avail_p"]} { + ad_returnredirect [ec_securelink [ec_url]checkout] + ad_script_abort + } + } +} + +# Everything is ok now; the user has a non-empty in_basket order and +# an address associated with it, so now get the other necessary +# information + +set form_action [ec_securelink [ec_url]select-shipping] +set rows_of_items "" +set shipping_avail_p 1 + +db_foreach get_shipping_data " + select p.no_shipping_avail_p, p.product_name, p.one_line_description, p.product_id, count(*) as quantity, u.offer_code, i.color_choice, i.size_choice, i.style_choice + from ec_orders o, ec_items i, ec_products p, (select offer_code, product_id + from ec_user_session_offer_codes usoc + where usoc.user_session_id=:user_session_id) u + where i.product_id=p.product_id + and o.order_id=i.order_id + and p.product_id= u.product_id(+) + and o.user_session_id=:user_session_id and o.order_state='in_basket' + group by p.no_shipping_avail_p, p.product_name, p.one_line_description, p.product_id, u.offer_code, i.color_choice, i.size_choice, i.style_choice" { + + if { [string compare $no_shipping_avail_p "t"] == 0 } { + set shipping_avail_p 0 + } + + set option_list [list] + if { ![empty_string_p $color_choice] } { + lappend option_list "Color: $color_choice" + } + if { ![empty_string_p $size_choice] } { + lappend option_list "Size: $size_choice" + } + if { ![empty_string_p $style_choice] } { + lappend option_list "Style: $style_choice" + } + set options [join $option_list ", "] + + # Trying out the fancy new . arrays. It would be much better to + # rework this for a 2D array,multiple setup, but I don't have time + # to think about it now... + + append rows_of_items " +Please verify that the items and quantities shown below are correct. Put a 0 (zero) in the + Quantity field to remove a particular item from your order.
+ + +
+ + + +Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-3.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-3.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-3.tcl 23 Jun 2005 12:28:22 -0000 1.1 @@ -0,0 +1,165 @@ +ad_page_contract { + + Users should get here from + process-order-quantity-payment-shipping.tcl; this page just + summarizes their order before they submit it. + + @param usca_p User session begun or not + @param referer Referring page + + @author + @creation-date + @author ported by Jerry Asher (jerry@theashergroup.com) + @author revised by Bart Teeuwisse (bart.teeuwisse@thecodemill.biz) + @revision-date April 2002 + +} { + usca_p:optional + referer:optional + + user_id:integer,notnull + participant_id:integer,optional +} + +ec_redirect_to_https_if_possible_and_necessary + +# Make sure we have all their necessary info, otherwise they probably got +# here via url surgery or by pushing Back + +# 1. There should be an in_basket order for their user_session_id. +# 2. The order should have the correct user_id associated with it. +# 3. The order should contain items. +# 4. The order should have an address associated with it. +# 5. The order should have credit card and shipping method associated with it. + +# We need them to be logged in + +#set user_id [ad_verify_and_get_user_id] +if {$user_id == 0} { + set return_url "[ad_conn url]" + ad_returnredirect "/register?[export_url_vars return_url]" + ad_script_abort +} + +# Make sure they have an in_basket order, otherwise they've probably +# gotten here by pushing Back, so return them to index.tcl + +set user_session_id [ec_get_user_session_id] +ec_create_new_session_if_necessary +set order_id [db_string get_order_id " + select order_id + from ec_orders + where user_session_id=:user_session_id + and order_state='in_basket'" -default ""] +if { [empty_string_p $order_id] } { + + # Then they probably got here by pushing "Back", so just redirect + # them to index.tcl + ns_log Notice "checkout-3.tcl ref(55): user_id:$user_id, user_session_id:$user_session_id, order_id is empty, redirecting to index" + rp_internal_redirect index + ad_script_abort +} + +# Make sure there's something in their shopping cart, otherwise +# redirect them to their shopping cart which will tell them that it's +# empty. + +if { [db_string get_ec_item_count " + select count(*) + from ec_items + where order_id=:order_id"] == 0 } { + ns_log Notice "checkout-3.tcl ref(68): order_id:$order_id, no items in basket, redirecting to shopping-cart" + rp_internal_redirect shopping-cart + ad_script_abort +} + +# Make sure the order belongs to this user_id, otherwise they managed +# to skip past checkout*.tcl, or they messed w/their user_session_id +# cookie + +set order_owner [db_string get_order_owner " + select user_id + from ec_orders + where order_id=:order_id"] +if { $order_owner != $user_id } { + ns_log Notice "checkout-3.tcl ref(82): order_owner:$order_owner not matching order_id:$order_id, redirecting to checkout" + rp_internal_redirect checkout + ad_script_abort +} + +# Make sure there is an address for this order, otherwise they've +# probably gotten here via url surgery, so redirect them to +# checkout.tcl + +# set address_id [db_string get_address_id " +# select shipping_address +# from ec_orders +# where order_id=$order_id" -default ""] +# if { [empty_string_p $address_id] } { + +# # No shipping address is needed if the order only consists of soft +# # goods not requiring shipping. + +# if {[db_0or1row shipping_avail " +# select p.no_shipping_avail_p, count (*) +# from ec_items i, ec_products p +# where i.product_id = p.product_id +# and p.no_shipping_avail_p = 'f' +# and i.order_id = :order_id +# group by no_shipping_avail_p"]} { +# ns_log Notice "checkout-3.tcl ref(110): no shipping address needed for order_id:$order_id, redirecting to checkout" +# ad_returnredirect [ec_securelink [ec_url]checkout] +# ad_script_abort +# } +# } + +# Make sure there is a credit card (or that the +# gift_certificate_balance covers the cost) and a shipping method for +# this order, otherwise they've probably gotten here via url surgery, +# so redirect them to checkout-2.tcl + +set creditcard_id [db_string get_creditcard_id " + select creditcard_id + from ec_orders + where order_id=:order_id" -default ""] +if { [empty_string_p $creditcard_id] } { + + # Ec_order_cost returns price + shipping + tax - gift_certificate + # BUT no gift certificates have been applied to in_basket orders, + # so this just returns price + shipping + tax + + set order_total_price_pre_gift_certificate [db_string get_pre_gc_price " + select ec_order_cost(:order_id) + from dual"] + set gift_certificate_balance [db_string get_gc_balance " + select ec_gift_certificate_balance(:user_id) + from dual"] + if { $gift_certificate_balance < $order_total_price_pre_gift_certificate } { + set gift_certificate_covers_cost_p "f" + } else { + set gift_certificate_covers_cost_p "t" + } +} + +# set shipping_method [db_string get_shipping_method " +# select shipping_method +# from ec_orders +# where order_id=:order_id" -default ""] +# if { [empty_string_p $shipping_method] || ([empty_string_p $creditcard_id] && [exists_and_equal gift_certificate_covers_cost_p "f"]) } { +# ns_log Notice "checkout-3.tcl ref(146): no shipping method for order_id:$order_id. Redirecting to checkout-2" +# rp_internal_redirect checkout-2 +# ad_script_abort +# } + +# Done with all the checks. Their order is ready to go! Now show +# them a summary before they submit their order +#if {[exists_and_equal referer "checkout-one-form-2"]} { + set display_progress "f" +#} else { +# set display_progress "t" +#} + +set order_summary [ec_order_summary_for_customer $order_id $user_id] +set context_bar [template::adp_parse [acs_root_dir]/packages/[ad_conn package_key]/www/contextbar [list context_addition [list "Completing Your Order"]]] +set ec_system_owner [ec_system_owner] +db_release_unused_handles Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-3.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-3.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout-3.xql 23 Jun 2005 12:28:22 -0000 1.1 @@ -0,0 +1,54 @@ + + +
The claim check you have entered is invalid. Please re-check it.
+The claim check is case sensitive; enter it exactly as shown on your gift certificate.
" + set prob_details " + Incorrect gift certificate claim check entered at [ad_conn url]. + Claim check entered: $claim_check by user ID: $user_id. + They may have just made a typo but if this happens repeatedly from the same IP address ([ns_conn peeraddr]) you may wish to look into this." + db_dml insert_error_failed_gc_claim " + insert into ec_problems_log + (problem_id, problem_date, problem_details) + values + (ec_problem_id_sequence.nextval, sysdate,:prob_details )" + ad_script_abort + } + + # There is a gift certificate with that claim check; + # now check whether it's already been claimed + # and, if so, whether it was claimed by this user + + db_1row get_gc_user_id " + select user_id as gift_certificate_user_id, amount + from ec_gift_certificates + where gift_certificate_id = :gift_certificate_id" + + if { [empty_string_p $gift_certificate_user_id ] } { + + # Then no one has claimed it, so go ahead and assign it to them + + db_dml update_ec_cert_set_user " + update ec_gift_certificates + set user_id=:user_id, claimed_date = sysdate + where gift_certificate_id = :gift_certificate_id" + set title "Gift Certificate Claimed" + set certificate_added_p "true" + } else { + + # It's already been claimed. See if it was claimed by a different + # user and, if so, record the problem + + if { $user_id != $gift_certificate_user_id } { + + set prob_details " + User ID $user_id tried to claim gift certificate $gift_certificate_id at [ad_conn url], but it had already been claimed by User ID $gift_certificate_id." + + db_dml insert_other_claim_prob " + insert into ec_problems_log + (problem_id, problem_date, gift_certificate_id, problem_details) + values + (ec_problem_id_sequence.nextval, sysdate, :gift_certificate_id, :prob_details)" + } + + set title "Gift Certificate Already Claimed" + set certificate_added_p "false" + } +} + + +# following mainly from process-order-quanity-shipping.tcl + +# update shipping method + +# 1. Update the shipping method and tax status + +if {[info exists shipping_gateway] && [string equal $shipping_gateway "true"]} { + + # A shipping gateway has been used. The shipping method contains + # both the shipping service level and the associated total + # charges. + + array set shipping_service_and_rate $shipping_method + set shipping_method $shipping_service_and_rate(service_description) + set order_shipping_cost $shipping_service_and_rate(total_charges) +} + +if {![info exists tax_exempt_p]} { + set tax_exempt_p "f" +} +if {[empty_string_p $tax_exempt_p]} { + set tax_exempt_p "f" +} + +if {![info exists shipping_method]} { + # shipping method does not exist + set shipping_method "" +} + +db_dml update_shipping_method " + update ec_orders + set shipping_method = :shipping_method, tax_exempt_p = :tax_exempt_p + where order_id = :order_id" + +# 2. Put the prices into ec_items + +# Set some things to use as arguments when setting prices + +if { [ad_parameter -package_id [ec_id] UserClassApproveP ecommerce] } { + set additional_user_class_restriction "and user_class_approved_p = 't'" +} else { + set additional_user_class_restriction "and (user_class_approved_p is null or user_class_approved_p='t')" +} + +set user_class_id_list [db_list get_list_user_classes " + select user_class_id + from ec_user_class_user_map + where user_id = :user_id $additional_user_class_restriction"] + +if {[info exists shipping_gateway] && [string equal $shipping_gateway "true"]} { + + # A shipping gateway has been used to calculate the total shipping + # charges so there is no to calculate the charges per item. + + set default_shipping_per_item 0 + set weight_shipping_cost 0 + set add_exp_amount_per_item 0 + set add_exp_amount_by_weight 0 +} else { + if {![info exists shipping_method]} { + # shipping method does not exist + set shipping_method "" + } + + if { $shipping_method != "pickup" && $shipping_method != "no shipping" } { + db_1row get_shipping_per_item " + select default_shipping_per_item, weight_shipping_cost + from ec_admin_settings" + db_1row get_exp_amt_peritem " + select add_exp_amount_per_item, add_exp_amount_by_weight + from ec_admin_settings" + } else { + set default_shipping_per_item 0 + set weight_shipping_cost 0 + set add_exp_amount_per_item 0 + set add_exp_amount_by_weight 0 + } +} +set usps_abbrev [db_string get_usps_abbrev " + select usps_abbrev + from ec_addresses + where address_id = :address_id" -default ""] +if { ![empty_string_p $usps_abbrev] && [string equal $tax_exempt_p "f"] } { + if { [db_0or1row get_tax_rate " + select tax_rate, shipping_p + from ec_sales_tax_by_state + where usps_abbrev = :usps_abbrev"] == 0 } { + set tax_rate 0 + set shipping_p f + } +} else { + set tax_rate 0 + set shipping_p f +} + +# These will be updated as we loop through the items + +set total_item_shipping_tax 0 +set total_item_price_tax 0 + +db_foreach get_items_in_cart " + select i.item_id, i.product_id, u.offer_code + from ec_items i, (select * + from ec_user_session_offer_codes usoc + where usoc.user_session_id = :user_session_id) u + where i.product_id=u.product_id(+) + and i.order_id=:order_id" { + + set everything [ec_price_price_name_shipping_price_tax_shipping_tax_for_one_item $product_id $offer_code $item_id $order_id $user_class_id_list \ + $shipping_method $default_shipping_per_item $weight_shipping_cost $add_exp_amount_per_item $add_exp_amount_by_weight $tax_rate $shipping_p] + set total_item_shipping_tax [expr $total_item_shipping_tax + [lindex $everything 4]] + set total_item_price_tax [expr $total_item_price_tax + [lindex $everything 3]] + set price_charged [lindex $everything 0] + set price_name [lindex $everything 1] + set shipping_charged [lindex $everything 2] + set tax_charged [lindex $everything 3] + set shipping_tax [lindex $everything 4] + + db_dml update_ec_items " + update ec_items + set price_charged = round(:price_charged,2), price_name = :price_name, shipping_charged = round(:shipping_charged,2), + price_tax_charged = round(:tax_charged,2), shipping_tax_charged = round(:shipping_tax,2) + where item_id = :item_id" + + # Get associated application assessments + set assessment_ids [list] + if { [db_0or1row get_assessment { + select c.assessment_id + + from dotlrn_ecommerce_section s, + dotlrn_catalogi c, + cr_items i + + where s.course_id = c.item_id + and c.item_id = i.item_id + and i.live_revision = c.course_id + and s.product_id = :product_id + + limit 1 + }] } { + if { [lsearch $assessment_ids $assessment_id] == -1 && ! [empty_string_p $assessment_id] && $assessment_id != -1 } { + lappend assessment_ids $assessment_id + } + } +} + +# 3. Determine base shipping cost & put it into ec_orders + +if {![info exists shipping_gateway]} { + + if {![info exists shipping_method]} { + # shipping_method does not exist + set shipping_method "" + } + + if { $shipping_method != "pickup" && $shipping_method != "no shipping" } { + set order_shipping_cost [db_string get_base_ship_cost " + select nvl(base_shipping_cost,0) + from ec_admin_settings"] + } else { + set order_shipping_cost 0 + } + + # Add on the extra base cost for express shipping, if appropriate + + if { [string equal $shipping_method "express"] } { + set add_exp_base_shipping_cost [db_string get_exp_base_cost " + select nvl(add_exp_base_shipping_cost,0) + from ec_admin_settings"] + set order_shipping_cost [expr $order_shipping_cost + $add_exp_base_shipping_cost] + } +} + +set tax_on_order_shipping_cost [db_string get_shipping_tax " + select ec_tax(0,:order_shipping_cost,:order_id) + from dual"] + +db_dml set_shipping_charges " + update ec_orders + set shipping_charged = round(:order_shipping_cost,2), shipping_tax_charged = round(:tax_on_order_shipping_cost,2) + where order_id=:order_id" + +# following mainly from process-payment.tcl + +# Now do error checking; It is required that either +# (a) their gift_certificate_balance covers the total order price, or +# (b) they've selected a previous credit card (and creditcard_number is null, +# otherwise we assume they want to use a new credit card), or +# (c) *all* of the credit card information for a new card has been filled in + +# we only want price and shipping from this (to determine whether +# gift_certificate_balance covers cost) + +set price_shipping_gift_certificate_and_tax [ec_price_shipping_gift_certificate_and_tax_in_an_order $order_id] +set order_total_price_pre_gift_certificate [expr [lindex $price_shipping_gift_certificate_and_tax 0] + [lindex $price_shipping_gift_certificate_and_tax 1]] +set gift_certificate_balance [db_string get_gc_balance " + select ec_gift_certificate_balance(:user_id) + from dual"] +if { $gift_certificate_balance >= $order_total_price_pre_gift_certificate } { + set gift_certificate_covers_cost_p "t" +} else { + set gift_certificate_covers_cost_p "f" +} + +if { [info exists creditcard_number] } { + + # get rid of spaces and dashes + + regsub -all -- "-" $creditcard_number "" creditcard_number + regsub -all " " $creditcard_number "" creditcard_number +} + +if { [string equal $gift_certificate_covers_cost_p "f"] } { + + if { $method == "cc" } { + if { ![info exists creditcard_id] || ([info exists creditcard_number] && ![empty_string_p $creditcard_number]) } { + if { ![info exists creditcard_number] || [empty_string_p $creditcard_number] } { + + # Then they haven't selected a previous credit card nor + # have they entered new credit card info + + ad_return_complaint 1 "To complete your order, submit this form, and confirm the information + on the following page.
+ +Alternately, you can use a multi-page order process, + if you prefer using some of your other addresses on file with us. +
+1. Please review your order list for accuracy.
+2. Complete this information.
+ +
+
+Shipping information+ + @shipping_options;noquote@ + |
+ Your gift certificate balance covers the total cost of your + order. No need to enter any payment information! +Your gift certificate balance takes care of + @certificate_amount@ of your order! Please enter credit card + information to pay for the rest. + |
Since we already have a credit card on file for you, you + can just click on the button next to it to use it for this + order.
+@old_cards_to_choose_from;noquote@
+Or enter a new credit card:
+If you're using a new card, please enter the full credit card number below.
+Credit card information | |
Credit card number: | ++ |
Type: | ++ |
Expires: | +@ec_expires_widget;noquote@ | +
+ No
Shipping method:
++ + $service_description + | ++ | ++ [string map {USD $} $value_currency_code] + | ++ $total_charges + | +
We need your shipping address before we can quote a shipping price. You will be able to review your order and shipping charge before confirming the order. |
Shipping method:
+Standard Shipping ($total_reg_shipping_price)
"
+
+ if { [ad_parameter -package_id [ec_id] ExpressShippingP ecommerce] } {
+ append shipping_options "
+ Express ($total_exp_shipping_price)
"
+ }
+ if { [ad_parameter -package_id [ec_id] PickupP ecommerce] } {
+ append shipping_options "
+ Pickup ($shipping_method_pickup)"
+ }
+ append shipping_options "
+ | Card Type | +Last 4 Digits | +Expires | +
+ | +[ec_pretty_creditcard_type $creditcard_type] | +$creditcard_last_four | +$creditcard_expire | +
class="altback"> |
+ class="altback">---> |
+ class="altback"> |
+ class="altback">---> |
+ class="altback"> |
+ class="altback">---> |
+ class="altback"> |
+ class="altback">---> |
+ class="altback"> |
+ class="altback">---> |
+ class="altback"> |
+
+ + +Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout.tcl 23 Jun 2005 12:28:21 -0000 1.1 @@ -0,0 +1,103 @@ +ad_page_contract { + @param usca_p:optional + + @author + @creation-date + @author ported by Jerry Asher (jerry@theashergroup.com) + @author revised by Bart Teeuwisse (bart.teeuwisse@thecodemill.biz) + @revision-date April 2002 +} { + usca_p:optional +} + + ec_redirect_to_https_if_possible_and_necessary + +# Make sure they have an in_basket order, otherwise they've probably +# gotten here by pushing Back, so return them to index.tcl + +# We need them to be logged in +set user_id [ad_conn user_id] + +if {$user_id == 0} { + set return_url "[ad_conn url]?[export_entire_form_as_url_vars]" + ad_returnredirect "/register?[export_url_vars return_url]" + ad_script_abort +} + + +set user_session_id [ec_get_user_session_id] +ec_create_new_session_if_necessary + +ec_log_user_as_user_id_for_this_session + +set order_id [db_string get_order_id " + select order_id + from ec_orders + where user_session_id = :user_session_id + and order_state='in_basket'" -default "" ] + +if { [empty_string_p $order_id] } { + + # Then they probably got here by pushing "Back", so just redirect + # them to index.tcl + + rp_internal_redirect index + ad_script_abort +} else { + db_dml update_ec_order_set_uid " + update ec_orders + set user_id = :user_id + where order_id = :order_id" +} + +# See if there are any saved shipping addresses for this user + +set address_type "shipping" + +# Check if the order requires shipping + +if {[db_0or1row shipping_avail " + select p.no_shipping_avail_p + from ec_items i, ec_products p + where i.product_id = p.product_id + and p.no_shipping_avail_p = 'f' + and i.order_id = :order_id + group by no_shipping_avail_p"]} { + + set shipping_required true + + # Set the referer to the name of this page so that the user + # returns to this page when the changes to the address have been + # checked. + + set referer checkout + # Present all saved addresses + + template::query get_user_addresses addresses multirow " + select address_id, attn, line1, line2, city, usps_abbrev, zip_code, phone, country_code, full_state_name, phone_time, address_type + from ec_addresses + where user_id=:user_id + and address_type = 'shipping'" -eval { + + set row(formatted) [ec_display_as_html [ec_pretty_mailing_address_from_args $row(line1) $row(line2) $row(city) $row(usps_abbrev) $row(zip_code) $row(country_code) \ + $row(full_state_name) $row(attn) $row(phone) $row(phone_time)]] + set address_id $row(address_id) + set row(delete) "[export_form_vars address_id referer]" + set row(edit) "[export_form_vars address_id address_type referer]" + set row(use) "[export_form_vars address_id]" + } + set hidden_form_vars [export_form_vars address_type referer] + +} else { + set shipping_required false +} + +if { $shipping_required == "false" } { + set address_id "" + ad_returnredirect "checkout-2?[export_url_vars address_id address_type]" + ad_script_abort +} + +set context_bar [template::adp_parse [acs_root_dir]/packages/[ad_conn package_key]/www/contextbar [list context_addition [list "Completing Your Order"]]] +set ec_system_owner [ec_system_owner] +db_release_unused_handles Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/checkout.xql 23 Jun 2005 12:28:21 -0000 1.1 @@ -0,0 +1,42 @@ + + +++ ++
++ +Select an address listed below or enter a new address.
++ + + + + + + ++ @addresses.formatted;noquote@ + ++ ++
++ ++ + ++ + ++ + ++ + ++ + ++
+ ++ ++ + ++ or + ++ + +
There has been an error in the processing of your credit card information. + Please contact [ec_system_owner] to report the error.
" + ad_script_abort + } + } + } else { + + # The applied certificates do no cover the cost of the + # soft goods. + + if {$applied_certificate_amount >= [expr $hard_goods_cost + $hard_goods_tax + $hard_goods_shipping + $hard_goods_shipping_tax + \ + $order_shipping + $order_shipping_tax]} { + + # The applied certificates cover the cost of the hard + # goods but not the soft goods. Create a new financial + # transaction. + + set transaction_id [db_nextval ec_transaction_id_sequence] + set transaction_amount [expr $soft_goods_cost + $soft_goods_tax - \ + [expr $applied_certificate_amount - [expr $hard_goods_cost + $hard_goods_tax + $hard_goods_shipping + $hard_goods_shipping_tax + \ + $order_shipping + $order_shipping_tax]]] + db_dml insert_financial_transaction " + insert into ec_financial_transactions + (transaction_id, order_id, transaction_amount, transaction_type, inserted_date) + values + (:transaction_id, :order_id, :transaction_amount, 'charge', sysdate)" + + array set response [ec_creditcard_authorization $order_id $transaction_id] + set result $response(response_code) + set transaction_id $response(transaction_id) + if { [string equal $result "authorized"] } { + ec_email_new_order $order_id + + # Change the order state from 'confirmed' to + # 'authorized'. + + ec_update_state_to_authorized $order_id + + # Record the date & time of the authorization and + # schedule the transaction for settlement. + + db_dml schedule_settlement " + update ec_financial_transactions + set authorized_date = sysdate, to_be_captured_p = 't', to_be_captured_date = sysdate + where transaction_id = :transaction_id" + + # Mark the transaction now, rather than waiting + # for the scheduled procedures to mark the + # transaction. + + array set response [ec_creditcard_marking $transaction_id] + set mark_result $response(response_code) + set pgw_transaction_id $response(transaction_id) + if { [string equal $mark_result "invalid_input"]} { + set problem_details " + When trying to mark the transaction for the items that don't require shipment (transaction $transaction_id) at [ad_conn url], the following result occurred: $mark_result" + db_dml record_marking_problem " + insert into ec_problems_log + (problem_id, problem_date, problem_details, order_id) + values + (ec_problem_id_sequence.nextval, sysdate, :problem_details, :order_id)" + } elseif {[string equal $mark_result "success"]} { + db_dml update_marked_date " + update ec_financial_transactions + set marked_date = sysdate + where transaction_id = :pgw_transaction_id" + } + + ad_returnredirect $return_url + + } elseif { [string equal $result "failed_authorization"] || [string equal $result "no_recommendation"] } { + + # If the gateway returns no recommendation then + # possibility remains that the card is invalid and + # that soft goods have been 'shipped' because the + # gateway was down and could not verify the soft + # goods transaction. The store owner then depends + # on the honesty of visitor to obtain a new valid + # credit card for the 'shipped' products. + + if {[string equal $result "no_recommendation"] } { + + # Therefor reject the transaction and ask for + # (a new credit card and ask) the visitor to + # retry. Most credit card gateways have + # uptimes close to 99% so this scenario should + # not happen often. Another reason for + # rejecting transactions without + # recommendation is that the scheduled + # procedures can't authorize soft goods + # transactions properly. + + db_dml set_transaction_failed " + update ec_financial_transactions + set failed_p = 't' + where transaction_id = :transaction_id" + + } + + # Updates everything that needs to be updated if a + # confirmed order fails + + ec_update_state_to_in_basket $order_id + ns_log Notice "finalize-order.tcl ref(411): updated creditcard check failed for order_id $order_id. Redirecting to credit-card-correction" + rp_form_put user_id $user_id + rp_internal_redirect credit-card-correction + ad_script_abort + } else { + + # Then result is probably "invalid_input". This should never + # occur + + ns_log Notice "Order $order_id received a result of $result" + ad_return_error "Sorry" " +There has been an error in the processing of your credit card information. + Please contact [ec_system_owner] to report the error.
" + } + } else { + + # The applied certificates cover neither the cost of + # the hard goods nor the soft goods. Create separate + # transactions for the soft goods and the hard goods. + + set transaction_id [db_nextval ec_transaction_id_sequence] + set transaction_amount [expr $soft_goods_cost + $soft_goods_tax - $applied_certificate_amount] + db_dml insert_financial_transaction " + insert into ec_financial_transactions + (transaction_id, order_id, transaction_amount, transaction_type, inserted_date) + values + (:transaction_id, :order_id, :transaction_amount, 'charge', sysdate)" + + array set response [ec_creditcard_authorization $order_id $transaction_id] + set result $response(response_code) + set soft_goods_transaction_id $response(transaction_id) + if { [string equal $result "authorized"] } { + ec_email_new_order $order_id + + # Record the date & time of the soft goods + # authorization. + + set transaction_id $soft_goods_transaction_id + db_dml update_authorized_date " + update ec_financial_transactions + set authorized_date = sysdate + where transaction_id = :transaction_id" + + # Calculate the transaction amount for the hard + # goods. + + set transaction_amount [expr $hard_goods_cost + $hard_goods_tax + $hard_goods_shipping + $hard_goods_shipping_tax + $order_shipping + $order_shipping_tax + \ + $soft_goods_cost + $soft_goods_tax - $transaction_amount] + set transaction_id [db_nextval ec_transaction_id_sequence] + db_dml insert_financial_transaction " + insert into ec_financial_transactions + (transaction_id, order_id, transaction_amount, transaction_type, inserted_date) + values + (:transaction_id, :order_id, :transaction_amount, 'charge', sysdate)" + + array set response [ec_creditcard_authorization $order_id $transaction_id] + set result $response(response_code) + set hard_goods_transaction_id $response(transaction_id) + if { [string equal $result "authorized"] } { + + # Both transactions are approved. Change the + # order state from 'confirmed' to + # 'authorized'. + + ec_update_state_to_authorized $order_id + + # Schedule the soft goods transaction for + # settlement. + + set transaction_id $soft_goods_transaction_id + db_dml schedule_settlement_soft_goods " + update ec_financial_transactions + set to_be_captured_p = 't', to_be_captured_date = sysdate + where transaction_id = :transaction_id" + + # Mark the transaction now, rather than + # waiting for the scheduled procedures to mark + # the transaction. + + array set response [ec_creditcard_marking $transaction_id] + set mark_result $response(response_code) + set pgw_transaction_id $response(transaction_id) + if { [string equal $mark_result "invalid_input"]} { + set problem_details " + When trying to mark the transaction for the items that don't require shipment (transaction $transaction_id) at [ad_conn url], the following result occurred: $mark_result" + db_dml record_marking_problem " + insert into ec_problems_log + (problem_id, problem_date, problem_details, order_id) + values + (ec_problem_id_sequence.nextval, sysdate, :problem_details, :order_id)" + } elseif {[string equal $mark_result "success"]} { + db_dml update_marked_date " + update ec_financial_transactions + set marked_date = sysdate + where transaction_id = :pgw_transaction_id" + } + + # Record the date & time of the hard goods + # authorization. + + set transaction_id $hard_goods_transaction_id + db_dml update_authorized_date " + update ec_financial_transactions + set authorized_date = sysdate + where transaction_id = :transaction_id" + + ad_returnredirect $return_url + + } elseif {[string equal $result "failed_authorization"] || [string equal $result "no_recommendation"] } { + + # Record both transactions as failed and ask + # for a new credit card number. The second + # transaction could have failed because it + # maxed out the card. Both transactions need + # to failed as the user might choose to use a + # different card and this procedure doesn't + # check for prior authorized transactions. + + set transaction_id $soft_goods_transaction_id + db_dml set_transaction_failed " + update ec_financial_transactions + set failed_p = 't' + where transaction_id = :transaction_id" + + set transaction_id $hard_goods_transaction_id + db_dml set_transaction_failed " + update ec_financial_transactions + set failed_p = 't' + where transaction_id = :transaction_id" + + # Updates everything that needs to be updated if a + # confirmed order fails + + ec_update_state_to_in_basket $order_id + ns_log Notice "finalize-order.tcl ref(544): creditcard check failed. Redirecting user to credit-card-correction." + rp_form_put user_id $user_id + rp_internal_redirect credit-card-correction + + } else { + + # Then result is probably + # "invalid_input". This should never occur + + ns_log Notice "Order $order_id received a result of $result" + ad_return_error "Sorry" " +There has been an error in the processing of your credit card information. + Please contact [ec_system_owner] to report the error.
" + } + } elseif { [string equal $result "failed_authorization"] || [string equal $result "no_recommendation"] } { + + set transaction_id $soft_goods_transaction_id + db_dml set_transaction_failed " + update ec_financial_transactions + set failed_p = 't' + where transaction_id = :transaction_id" + + # Updates everything that needs to be updated if a + # confirmed order fails + + ec_update_state_to_in_basket $order_id + + rp_form_put user_id $user_id + rp_internal_redirect credit-card-correction + ad_script_abort + } else { + + # Then result is probably "invalid_input". This should never + # occur + + ns_log Notice "Order $order_id received a result of $result" + ad_return_error "Sorry" " +There has been an error in the processing of your credit card information. + Please contact [ec_system_owner] to report the error.
" + } + } + } + } else { + + # The order contains only hard goods that come at a cost. + + if {$applied_certificate_amount >= [expr $hard_goods_cost + $hard_goods_tax + $hard_goods_shipping + $hard_goods_shipping_tax + $order_shipping + $order_shipping_tax]} { + + # The applied certificates cover the cost of the hard + # goods. No financial transaction required. + + # Mail the confirmation e-mail to the user. + + ec_email_new_order $order_id + + # Change the order state from 'confirmed' to + # 'authorized'. + + ec_update_state_to_authorized $order_id + ad_returnredirect $return_url + + } else { + + # The applied certificates only partially covered the cost + # of the hard goods. Create a new financial transaction. + + set transaction_id [db_nextval ec_transaction_id_sequence] + set transaction_amount [expr $hard_goods_cost + $hard_goods_tax + $hard_goods_shipping + $hard_goods_shipping_tax + $order_shipping + $order_shipping_tax - \ + [expr $applied_certificate_amount - $soft_goods_cost - $soft_goods_tax]] + db_dml insert_financial_transaction " + insert into ec_financial_transactions + (transaction_id, order_id, transaction_amount, transaction_type, inserted_date) + values + (:transaction_id, :order_id, :transaction_amount, 'charge', sysdate)" + + array set response [ec_creditcard_authorization $order_id $transaction_id] + set result $response(response_code) + set transaction_id $response(transaction_id) + if { [string equal $result "authorized"] } { + ec_email_new_order $order_id + + # Change the order state from 'confirmed' to + # 'authorized'. + + ec_update_state_to_authorized $order_id + + # Record the date & time of the authorization. + + db_dml update_authorized_date " + update ec_financial_transactions + set authorized_date = sysdate + where transaction_id = :transaction_id" + } + + if { [string equal $result "authorized"] || [string equal $result "no_recommendation"] } { + ad_returnredirect $return_url + ad_script_abort + } elseif { [string equal $result "failed_authorization"] } { + + # If the gateway returns no recommendation then + # possibility remains that the card is invalid and + # that soft goods have been 'shipped' because the + # gateway was down and could not verify the soft goods + # transaction. The store owner then depends on the + # honesty of visitor to obtain a new valid credit card + # for the 'shipped' products. + + if {[string equal $result "no_recommendation"] } { + + # Therefor reject the transaction and ask for (a + # new credit card and ask) the visitor to + # retry. Most credit card gateways have uptimes + # close to 99% so this scenario should not happen + # often. Another reason for rejecting transactions + # without recommendation is that the scheduled + # procedures can't authorize soft goods + # transactions properly. + + db_dml set_transaction_failed " + update ec_financial_transactions + set failed_p = 't' + where transaction_id = :transaction_id" + + } + + # Updates everything that needs to be updated if a + # confirmed order fails + + ec_update_state_to_in_basket $order_id + + # log this just in case this is a symptom of an extended gateway downtime + ns_log Notice "finalize-order.tcl, ref(671): creditcard check failed for order_id $order_id. Redirecting to credit-card-correction" + + rp_form_put user_id $user_id + rp_internal_redirect credit-card-correction + ad_script_abort + } else { + + # Then result is probably "invalid_input". This should never + # occur + + ns_log Notice "Order $order_id received a result of $result" + ad_return_error "Sorry" " +There has been an error in the processing of your credit card information. + Please contact [ec_system_owner] to report the error.
" + } + } + } +} else { + + # The order does not contain any hard goods that come at a cost. + + if {$soft_goods_cost > 0} { + + # The order contains only soft goods that come at a cost. + + if {$applied_certificate_amount >= [expr $soft_goods_cost + $soft_goods_tax]} { + + # The gift certificates cover the cost of the soft + # goods. No financial transaction required. Mail a + # confirmation e-mail to the user. + + ec_email_new_order $order_id + + # Change the order state from 'confirmed' to + # 'authorized'. + + ec_update_state_to_authorized $order_id + ad_returnredirect $return_url + + } else { + + # The certificates only partially cover the cost of the + # soft goods. Create a new financial transaction + + set transaction_id [db_nextval ec_transaction_id_sequence] + set transaction_amount [expr $soft_goods_cost + $soft_goods_tax - $applied_certificate_amount] + db_dml insert_financial_transaction " + insert into ec_financial_transactions + (transaction_id, order_id, transaction_amount, transaction_type, inserted_date) + values + (:transaction_id, :order_id, :transaction_amount, 'charge', sysdate)" + + array set response [ec_creditcard_authorization $order_id $transaction_id] + set result $response(response_code) + set transaction_id $response(transaction_id) + if { [string equal $result "authorized"] } { + ec_email_new_order $order_id + + # Change the order state from 'confirmed' to + # 'authorized'. + + ec_update_state_to_authorized $order_id + + # Record the date & time of the authorization and + # schedule the transaction for settlement. + + db_dml schedule_settlement " + update ec_financial_transactions + set authorized_date = sysdate, to_be_captured_p = 't', to_be_captured_date = sysdate + where transaction_id = :transaction_id" + + # Mark the transaction now, rather than waiting for + # the scheduled procedures to mark the transaction. + + array set response [ec_creditcard_marking $transaction_id] + set mark_result $response(response_code) + set pgw_transaction_id $response(transaction_id) + if { [string equal $mark_result "invalid_input"]} { + set problem_details " + When trying to mark the transaction for the items that don't require shipment (transaction $transaction_id) at [ad_conn url], the following result occurred: $mark_result" + db_dml record_marking_problem " + insert into ec_problems_log + (problem_id, problem_date, problem_details, order_id) + values + (ec_problem_id_sequence.nextval, sysdate, :problem_details, :order_id)" + } elseif {[string equal $mark_result "success"]} { + db_dml update_marked_date " + update ec_financial_transactions + set marked_date = sysdate + where transaction_id = :pgw_transaction_id" + } + ad_returnredirect $return_url + } + + if {[string equal $result "failed_authorization"] || [string equal $result "no_recommendation"] } { + + # If the gateway returns no recommendation then the + # possibility remains that the card is invalid and + # that soft goods have been 'shipped' because the + # gateway was down and could not verify the soft goods + # transaction. The store owner then depends on the + # honesty of visitor to obtain a new valid credit card + # for the 'shipped' products. + + if {[string equal $result "no_recommendation"] } { + + # Therefor reject the transaction and ask for (a + # new credit card and ask) the visitor to + # retry. Most credit card gateways have uptimes + # close to 99% so this scenario should not happen + # often. Another reason for rejecting transactions + # without recommendation is that the scheduled + # procedures can't authorize soft goods + # transactions properly. + + db_dml set_transaction_failed " + update ec_financial_transactions + set failed_p = 't' + where transaction_id = :transaction_id" + + } + + # Updates everything that needs to be updated if a + # confirmed order fails + + ec_update_state_to_in_basket $order_id + ns_log Notice "finalize-order.tcl ref(789): creditcard check failed. Redirecting to credit-card-correction" + rp_form_put user_id $user_id + rp_internal_redirect credit-card-correction + ad_script_abort + + } else { + + # Then result is probably "invalid_input". This should never + # occur + + ns_log Notice "Order $order_id received a result of $result" + ad_return_error "Sorry" " +There has been an error in the processing of your credit card information. + Please contact [ec_system_owner] to report the error.
" + } + } + } else { + + # The order contains neither hard nor soft goods that come at + # a cost. No financial transactions required. Mail the + # confirmation e-mail to the user. + + ec_email_new_order $order_id + + # Change the order state from 'confirmed' to + # 'authorized'. + + ec_update_state_to_authorized $order_id + ad_returnredirect $return_url + } +} Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/finalize-order.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/finalize-order.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/finalize-order.xql 23 Jun 2005 12:28:21 -0000 1.1 @@ -0,0 +1,83 @@ + + +Sorry, you have an order for which credit card authorization has not yet taken place. + Please wait for the authorization to complete before adding new items to your shopping cart.
+Thank you.
" + ns_log Warning "shopping-cart-add.tcl,line59: User tried to add an item to the shopping cart after making a purchase, but was rejected!" + ad_script_abort +} + +set order_id [db_string get_order_id " + select order_id + from ec_orders + where user_session_id = :user_session_id + and order_state = 'in_basket'" -default ""] + +# Here's the airtight way to do it: do the check on order_id, then +# insert a new order where there doesn't exist an old one, then set +# order_id again (because the correct order_id might not be the one +# set inside the if statement). It should now be impossible for +# order_id to be the empty string (if it is, log the error and +# redirect them to product.tcl). + +if { [value_if_exists order_id] < 1 || [ad_var_type_check_number_p $order_id] == 0 } { + set order_id [db_nextval ec_order_id_sequence] + + # Create the order (if an in_basket order *still* doesn't exist) + + db_dml insert_new_ec_order " + insert into ec_orders + (order_id, user_session_id, order_state, in_basket_date) + select :order_id, :user_session_id, 'in_basket', sysdate from dual + where not exists (select 1 from ec_orders where user_session_id = :user_session_id and order_state = 'in_basket')" + + # Now either an in_basket order should have been inserted by the + # above statement or it was inserted by a different thread + # milliseconds ago + + set order_id [db_string get_order_id " + select order_id + from ec_orders + where user_session_id = :user_session_id + and order_state = 'in_basket'" -default ""] + if { [empty_string_p $order_id] } { + + # I don't expect this to ever happen, but just in case, I'll + # log the problem and redirect them to product.tcl + + set errormsg "Null order_id on shopping-cart-add.tcl for user_session_id :user_session_id. Please report this problem to [ec_package_maintainer]." + db_dml insert_problem_into_log " + insert into ec_problems_log + (problem_id, problem_date, problem_details) + values + (ec_problem_id_sequence.nextval, sysdate,:errormsg)" + ad_returnredirect "product?[export_url_vars product_id]" + ad_script_abort + } +} + +# Insert an item into that order if an identical item doesn't exist +# (this is double click protection). If they want to update +# quantities, they can do so from the shopping cart page. + +# Bart Teeuwisse: Fine tuned the postgresql version to only reject +# items that were added to the shopping cart in the last 5 seconds. +# That should be enough to protect from double clicks yet provides a +# more intuitive user experience. + +# Roel: Participant also pays +if { $participant_id == 0 } { + set participant_id $user_id +} +for {set i 0} {$i < $item_count} {incr i} { + db_transaction { + set item_id [db_nextval ec_item_id_sequence] + + if { ( [exists_and_not_null participant_id] ) } { + set limit_order_p [expr ! [db_string order_exists { + select count(*) + from ec_items i, dotlrn_ecommerce_orders o, ec_orders eo + where i.item_id = o.item_id + and i.order_id = eo.order_id + and i.product_id = :product_id + and o.participant_id = :participant_id + and eo.order_state = 'in_basket' + and eo.user_session_id = :user_session_id + } -default 0]] + } else { + set limit_order_p 1 + } + + if { $limit_order_p } { + db_dml insert_new_item_in_order {} + + db_dml insert_new_item_order_dotlrn_ecommerce { + insert into dotlrn_ecommerce_orders (item_id, patron_id, participant_id) + values (:item_id, :user_id, :participant_id) + } + } + } +} + +db_release_unused_handles +ad_returnredirect [export_vars -base shopping-cart { user_id product_id }] \ No newline at end of file Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart-add.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart-add.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart-add.xql 23 Jun 2005 12:28:21 -0000 1.1 @@ -0,0 +1,23 @@ + + ++ We could not find any shopping cart for you. This may be because you have cookies + turned off on your browser. Cookies are necessary in order to have a shopping cart + system so that we can tell which items are yours. + +
+ In Netscape 4.0, you can enable cookies from Edit -> Preferences -> Advanced.
+
+ In Microsoft Internet Explorer 4.0, you can enable cookies from View ->
+ Internet Options -> Advanced -> Security.
+
+
+
+ [ec_continue_shopping_options]
+ "
+ ad_script_abort
+}
+
+set order_id [db_string get_order_id "select order_id from ec_orders where order_state='in_basket' and user_session_id=:user_session_id" -default ""]
+
+# if order_id is null, this probably means that they got to this page by pushing back
+# so just return them to their empty cart
+
+if { [empty_string_p $order_id] } {
+ rp_internal_redirect "shopping-cart"
+ ad_script_abort
+}
+
+db_foreach get_products_w_attribs "
+ select i.product_id,
+ i.color_choice,
+ i.size_choice,
+ i.style_choice,
+ count(*) as r_quantity
+ from ec_orders o,
+ ec_items i
+ where o.order_id=i.order_id
+ and o.user_session_id=:user_session_id
+ and o.order_state='in_basket'
+ group by i.product_id,
+ i.color_choice,
+ i.size_choice,
+ i.style_choice
+ " {
+
+ set pid_bak $product_id
+
+ set array_value [list $product_id $color_choice $size_choice $style_choice]
+ regsub -all "{" $array_value {} array_value
+ regsub -all "}" $array_value {} array_value
+
+ set real_quantity($array_value) $r_quantity
+}
+
+# quantity_to_add might be negative
+# also there are two special cases that may come about, for instace,
+# when a user pushes "Back" to get here after having altered their cart
+# (1) if quantity($product_id) exists but real_quantity($product_id)
+# doesn't exist, then ignore it (we're going to miss that
+# product_id anyway when looping through product_id_list)
+# (2) if real_quantity($product_id) exists but quantity($product_id)
+# doesn't exist then quantity_to_add will be 0
+
+# set product_id [lindex $product_color_size_style 0]
+# set color_choice [lindex $product_color_size_style 1]
+# set size_choice [lindex $product_color_size_style 2]
+# set style_choice [lindex $product_color_size_style 3]
+
+set max_quantity_to_add [parameter::get -parameter CartMaxToAdd]
+
+db_transaction {
+
+ foreach product_color_size_style [array names quantity] {
+
+ set product_lookup $product_color_size_style
+
+ regsub -all "{" $product_lookup {} product_lookup
+ regsub -all "}" $product_lookup {} product_lookup
+
+ if { [info exists real_quantity($product_lookup)] } {
+
+ set quantity_to_add "[expr $quantity($product_color_size_style) - $real_quantity($product_lookup)]"
+
+ set product_id [lindex $product_color_size_style 0]
+ set color_choice [lindex $product_color_size_style 1]
+ set size_choice [lindex $product_color_size_style 2]
+ set style_choice [lindex $product_color_size_style 3]
+
+ if { $quantity_to_add > 0 } {
+ set remaining_quantity [min $quantity_to_add $max_quantity_to_add]
+ while { $remaining_quantity > 0 } {
+
+ db_dml insert_new_quantity_to_add "insert into ec_items
+ (item_id, product_id, color_choice, size_choice, style_choice, order_id, in_cart_date)
+ values
+ (ec_item_id_sequence.nextval, :product_id, :color_choice, :size_choice, :style_choice, :order_id, sysdate)"
+ set remaining_quantity [expr $remaining_quantity - 1]
+ }
+ } elseif { $quantity_to_add < 0 } {
+ set remaining_quantity [expr abs($quantity_to_add)]
+
+ set rows_to_delete [list]
+ while { $remaining_quantity > 0 } {
+ # determine the rows to delete in ec_items (the last instance of this product within this order)
+ if { [llength $rows_to_delete] > 0 } {
+ set extra_condition "and item_id not in ([join $rows_to_delete ", "])"
+ } else {
+ set extra_condition ""
+ }
+ lappend rows_to_delete [db_string get_rows_to_delete "
+ select max(item_id)
+ from ec_items
+ where product_id=:product_id
+ and color_choice [ec_decode $color_choice "" "is null" "= :color_choice"]
+ and size_choice [ec_decode $size_choice "" "is null" "= :size_choice"]
+ and style_choice [ec_decode $style_choice "" "is null" "= :style_choice"]
+ and order_id=:order_id $extra_condition"]
+
+ set remaining_quantity [expr $remaining_quantity - 1]
+ }
+ db_dml delete_from_ec_items "delete from ec_items where item_id in ([join $rows_to_delete ", "])"
+ }
+ # otherwise, do nothing
+ }
+ }
+}
+
+db_release_unused_handles
+
+if { [info exists return_url] } {
+ ad_returnredirect $return_url
+} else {
+ rp_internal_redirect shopping-cart
+}
+
+
Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart-quantities-change.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart-quantities-change.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart-quantities-change.xql 23 Jun 2005 12:28:21 -0000 1.1
@@ -0,0 +1,41 @@
+
+
+ We need your shipping address before we can quote a shipping price. You are able to review your order and any shipping charges before confirming an order. If you were logged in, we could show you any associated shipping charges The following has beens sent to the purchaser
+
Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart.tcl 23 Jun 2005 12:28:21 -0000 1.1
@@ -0,0 +1,347 @@
+ad_page_contract {
+ @param usca_p User session begun or not
+
+ @author
+ @creation-date
+ @author ported by Jerry Asher (jerry@theashergroup.com)
+ @author revised by Bart Teeuwisse (bart.teeuwisse@thecodemill.biz)
+ @revision-date April 2002
+
+} {
+ usca_p:optional
+ product_id:optional
+
+ user_id:integer,notnull,optional
+}
+
+# bottom links:
+# 1) continue shopping (always)
+
+# Case 1) Continue shopping
+# Create the link now before the product_id gets overwritten when
+# looping through the products in the cart.
+
+set previous_product_id_p 0
+set previous_product_id 0
+
+if {[info exists product_id]} {
+ set previous_product_id_p 1
+ set previous_product_id $product_id
+}
+
+# We don't need them to be logged in, but if they are they might get a
+# lower price
+set first_names ""
+set last_name ""
+set email ""
+
+if { ! [info exists user_id] } {
+ set user_id [ad_verify_and_get_user_id]
+}
+if { $user_id != 0 } {
+ db_1row user_info {
+ select first_names, last_name, email
+ from dotlrn_users where user_id = :user_id
+ }
+}
+
+# user sessions:
+# 1. get user_session_id from cookie
+# 2. if user has no session (i.e. user_session_id=0), attempt to set it if it hasn't been
+# attempted before
+# 3. if it has been attempted before, give them message that we can't do shopping carts
+# without cookies
+
+set user_session_id [ec_get_user_session_id]
+ec_create_new_session_if_necessary [export_url_vars user_id]
+
+# This is not being used anywhere
+#set n_items_in_cart [db_string get_n_items "
+# select count(*)
+# from ec_orders o, ec_items i
+# where o.order_id=i.order_id
+# and o.user_session_id=:user_session_id and o.order_state='in_basket'"]
+
+# calculate shipping charge options when not using shipping-gateway,
+# and then include the value with each option (for an informed choice)
+
+# mainly from process-order-quantity-shipping.tcl
+
+# set initial values for itemization loop
+db_1row get_ec_admin_settings "
+ select nvl(base_shipping_cost,0) as base_shipping_cost,
+ nvl(default_shipping_per_item,0) as default_shipping_per_item,
+ nvl(weight_shipping_cost,0) as weight_shipping_cost,
+ nvl(add_exp_base_shipping_cost,0) as add_exp_base_shipping_cost,
+ nvl(add_exp_amount_per_item,0) as add_exp_amount_per_item,
+ nvl(add_exp_amount_by_weight,0) as add_exp_amount_by_weight
+ from ec_admin_settings"
+
+set last_product_id 0
+set product_counter 0
+set total_price 0
+set currency [parameter::get -parameter Currency]
+set max_add_quantity_length [string length [parameter::get -parameter CartMaxToAdd]]
+set offer_express_shipping_p [parameter::get -parameter ExpressShippingP]
+set offer_pickup_option_p [parameter::get -parameter PickupP]
+set total_reg_shipping_price 0
+set total_exp_shipping_price 0
+set no_shipping_options "t"
+# Check if a shipping gateway has been selected.
+set shipping_gateway [parameter::get -parameter ShippingGateway]
+set shipping_gateway_in_use [acs_sc_binding_exists_p ShippingGateway $shipping_gateway]
+set shipping_address_id 0
+
+if { $shipping_gateway_in_use} {
+ #this section mainly from select-shipping.tcl
+
+ # Replace the default ecommerce shipping calculations with the
+ # charges from the shipping gateway, which contains
+ # both the shipping service level and the associated total
+ # charges. Requries zipcode and country, so
+ # user needs to be logged in too.
+
+ if { $user_id != 0 } {
+ set shipping_address_ids [db_list get_shipping_address_ids "
+ select address_id
+ from ec_addresses
+ where user_id=:user_id
+ and address_type = 'shipping'" ]
+
+ if { [llength $shipping_address_ids] > 1 } {
+ # the max valued id is most likely the newest id (no last used date field available)
+ set shipping_address_id [ec_max_of_list $shipping_address_ids]
+ } elseif { $shipping_address_ids > 0 } {
+ set shipping_address_id $shipping_address_ids
+ } else {
+ set shipping_address_id 0
+ set shipping_options "
"
+ }
+ if { $shipping_address_id > 0 } {
+ # we have a zipcode and country
+ db_1row select_shipping_area "
+ select country_code, zip_code
+ from ec_addresses
+ where address_id = :shipping_address_id"
+
+ # Calculate the total value of the shipment.
+ set shipment_value 0
+ }
+ } else {
+ # user_id == 0
+ set shipping_options "
"
+ }
+}
+
+
+# adding some fields to handle calculating shipping prices
+# p.no_shipping_avail_p, p.shipping, p.shipping_additional, p.weight
+# basically collect shipping information for any items where ec_products.no_shipping_avail_p = 't'
+
+db_multirow -extend { line_subtotal patron_name participant_name participant_type } in_cart get_products_in_cart "
+ select p.product_name, p.one_line_description, p.no_shipping_avail_p, p.shipping, p.shipping_additonal, p.weight, p.product_id, count(*) as quantity, u.offer_code, i.color_choice, i.size_choice, i.style_choice, '' as price
+ from ec_orders o
+ join ec_items i on (o.order_id=i.order_id)
+ join ec_products p on (i.product_id=p.product_id)
+ left join (select product_id, offer_code
+ from ec_user_session_offer_codes usoc
+ where usoc.user_session_id=:user_session_id) u on (p.product_id=u.product_id)
+ where o.user_session_id=:user_session_id
+ and o.order_state='in_basket'
+ group by p.product_name, p.one_line_description, p.no_shipping_avail_p, p.shipping, p.shipping_additional, p.weight, p.product_id, u.offer_code, i.color_choice, i.size_choice, i.style_choice" {
+ set line_subtotal "$quantity"
+ if { ! [empty_string_p $patron_id] } {
+ set patron_name [person::name -person_id $patron_id]
+ }
+ if { ! [empty_string_p $participant_id] } {
+ set participant_type [acs_object_type $participant_id]
+ if { $participant_type == "user" } {
+ set participant_name [person::name -person_id $participant_id]
+ } else {
+ group::get -group_id $participant_id -array group
+ }
+ }
+ }
+
+for {set i 1} {$i <= [template::multirow size in_cart]} {incr i} {
+
+ set product_name [template::multirow get in_cart $i product_name]
+ set one_line_description [template::multirow get in_cart $i one_line_description]
+ set product_id [template::multirow get in_cart $i product_id]
+ set no_shipping_avail_p [template::multirow get in_cart $i no_shipping_avail_p]
+ set shipping [template::multirow get in_cart $i shipping]
+ set shipping_additional [template::multirow get in_cart $i shipping_additional]
+ set weight [template::multirow get in_cart $i weight]
+ set quantity [template::multirow get in_cart $i quantity]
+ set offer_code [template::multirow get in_cart $i offer_code]
+ set color_choice [template::multirow get in_cart $i color_choice]
+ set size_choice [template::multirow get in_cart $i size_choice]
+ set style_choice [template::multirow get in_cart $i style_choice]
+
+ set patron_id [template::multirow get in_cart $i patron_id]
+ set participant_id [template::multirow get in_cart $i participant_id]
+
+ set max_quantity_length [max $max_add_quantity_length [string length $quantity]]
+ # Deletions are done by product_id, color_choice, size_choice,
+ # style_choice, not by item_id because we want to delete the
+ # entire quantity of that product. Also print the price for a
+ # product of the selected options and the aforementioned delete
+ # option.
+
+ set price_line [ec_price_line $product_id $user_id $offer_code]
+ set delete_export_vars [export_url_vars product_id color_choice size_choice style_choice user_id patron_id participant_id]
+
+ # Too bad I have to do another call to get the price. That is
+ # because ec_price_line returns canned html instead of the price.
+
+ set lowest_price_and_price_name [ec_lowest_price_and_price_name_for_an_item $product_id $user_id $offer_code]
+ set lowest_price [lindex $lowest_price_and_price_name 0]
+
+
+ # Calculate line subtotal for end users
+ set line_subtotal [ec_pretty_price [expr $quantity * $lowest_price] $currency]
+ template::multirow set in_cart $i line_subtotal $line_subtotal
+
+ if { [string equal $no_shipping_avail_p "f"] && !$shipping_gateway_in_use} {
+ # at least one thing is shippable, begin calculating ship value(s)
+ set no_shipping_options "f"
+
+ # Calculate shipping for line item
+ set first_instance 1
+ set shipping_prices_for_first_line_item [ec_shipping_prices_for_one_item_by_rate $product_id $shipping $shipping_additional $default_shipping_per_item $weight $weight_shipping_cost $first_instance $add_exp_amount_per_item $add_exp_amount_by_weight]
+ set total_reg_shipping_price [expr $total_reg_shipping_price + [lindex $shipping_prices_for_first_line_item 0]]
+ set total_exp_shipping_price [expr $total_exp_shipping_price + [lindex $shipping_prices_for_first_line_item 1]]
+
+ if { $quantity > 1 } {
+ set first_instance 0
+ set shipping_prices_for_more_line_items [ec_shipping_prices_for_one_item_by_rate $product_id $shipping $shipping_additional $default_shipping_per_item $weight $weight_shipping_cost $first_instance $add_exp_amount_per_item $add_exp_amount_by_weight]
+ set total_reg_shipping_price [expr $total_reg_shipping_price + ( [lindex $shipping_prices_for_more_line_items 0] * ( $quantity - 1 ) ) ]
+ set total_exp_shipping_price [expr $total_exp_shipping_price + ( [lindex $shipping_prices_for_more_line_items 1] * ( $quantity - 1 ) ) ]
+
+ }
+ } elseif { $shipping_gateway_in_use && $shipping_address_id > 0 && [string equal $no_shipping_avail_p "f"] } {
+ set shipment_value [expr $shipment_value + [lindex [ec_lowest_price_and_price_name_for_an_item $product_id $user_id $offer_code] 0]]
+ }
+
+ # Add the price of the item to the total price
+
+ set total_price [expr $total_price + ($quantity * $lowest_price)]
+ incr product_counter $quantity
+
+ template::multirow set in_cart $i delete_export_vars $delete_export_vars
+ template::multirow set in_cart $i price "[lindex $lowest_price_and_price_name 1]: [ec_pretty_price [lindex $lowest_price_and_price_name 0] $currency]"
+
+}
+
+# Add adjust quantities line if there are products in the cart.
+set pretty_total_price [ec_pretty_price $total_price $currency]
+
+if { $shipping_gateway_in_use && $shipping_address_id > 0} {
+
+ set weight_unit_of_measure [parameter::get -parameter WeightUnits]
+
+ set shipping_options "
"
+}
+
+if { !$shipping_gateway_in_use } {
+ # Rate based shipping calculations
+ # 3. Determine base shipping costs that are separate from items
+
+ # set base shipping charges
+ set order_shipping_cost $base_shipping_cost
+ set shipping_method_standard $order_shipping_cost
+
+ # Add on the extra base cost for express shipping
+ set shipping_method_express [expr $order_shipping_cost + $add_exp_base_shipping_cost]
+
+ # 4. set total costs for each shipping option
+ set total_shipping_price_default $total_reg_shipping_price
+ set total_reg_shipping_price [ec_pretty_price [expr $total_reg_shipping_price + $shipping_method_standard] $currency "t"]
+ set total_exp_shipping_price [ec_pretty_price [expr $total_exp_shipping_price + $shipping_method_express] $currency "t"]
+ set shipping_method_pickup [ec_pretty_price 0 $currency "t"]
+ set shipping_method_no_shipping 0
+
+ # 5 prepare shipping options to present to user
+ if { [string equal $no_shipping_options "f" ] } {
+
+ # standard shipping is total_reg_shipping_price
+ set shipping_options "Shipping is addtional:"
+ if { $offer_express_shipping_p } {
+ # express shipping is total_exp_shipping_price
+ set shipping_options "Shipping is additional, choices are:"
+ }
+ if { $offer_pickup_option_p } {
+ # pickup instead of shipping is shipping_method_pickup
+ set shipping_options "Shipping is additional, choices are:"
+ }
+ } else {
+ set shipping_options "No shipping options available."
+ }
+}
+
+# List the states that get charged tax. Although not 100% accurate
+# as shipping might be taxed too this is better than nothing.
+
+db_multirow -extend { pretty_tax } tax_entries tax_states "
+ select tax_rate, initcap(state_name) as state
+ from ec_sales_tax_by_state tax, us_states state
+ where state.abbrev = tax.usps_abbrev" {
+ set pretty_tax "[format %0.2f [expr $tax_rate * 100]]%"
+}
+
+# bottom links:
+# 1) continue shopping (always and already created)
+# 2) log in (if they're not logged in)
+# 3) retrieve a saved cart (if they are logged in and they have a saved cart)
+# 4) save their cart (if their cart is not empty)
+
+if { $user_id == 0 } {
+
+ # Case 2) the user is not logged in.
+ set return_url [ns_urlencode "[ec_url]"]
+
+} else {
+ # Case 3) Retrieve saved carts
+ set saved_carts_p [db_string check_for_saved_carts "
+ select 1
+ from dual
+ where exists (
+ select 1
+ from ec_orders
+ where user_id=:user_id
+ and order_state='in_basket'
+ and saved_p='t')" -default ""]
+}
+
+set context_bar [template::adp_parse [acs_root_dir]/packages/[ad_conn package_key]/www/contextbar [list context_addition [list "Shopping Cart"]]]
+set context [list [list [export_vars -base ../admin/process-purchase-course { user_id }] "Process Purchase"] "Shopping Cart"]
+set ec_system_owner [ec_system_owner]
+db_release_unused_handles
+
+ad_return_template
Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/shopping-cart.xql 23 Jun 2005 12:28:21 -0000 1.1
@@ -0,0 +1,40 @@
+
+
+ "
+
+ # Get the list of services and their charges
+
+ set rates_and_services [lsort -index 1 -real \
+ [acs_sc_call "ShippingGateway" "RatesAndServicesSelection" \
+ [list "" "" "$country_code" "$zip_code" "$shipment_value" "$currency" "" "$weight_unit_of_measure"] "$shipping_gateway"]]
+
+ # Present the available shipping services to the user
+
+ foreach service $rates_and_services {
+ array set rate_and_service $service
+ set total_charges $rate_and_service(total_charges)
+ set service_code $rate_and_service(service_code)
+ set service_description [acs_sc_call "ShippingGateway" "ServiceDescription" "$service_code" "$shipping_gateway"]
+ set gateway_shipping_default_price $total_charges
+ append shipping_options "
+ Shipping method:
+ $service_description
+
+ [string map {USD $} $currency]
+
+ $total_charges
+ "
+ }
+ append shipping_options "
+
+
+
+
+
Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/thank-you.tcl
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/thank-you.tcl,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/thank-you.tcl 23 Jun 2005 12:28:21 -0000 1.1
@@ -0,0 +1,64 @@
+ad_page_contract {
+ @param usca_p User session begun or not
+
+ @author
+ @creation-date
+ @author ported by Jerry Asher (jerry@theashergroup.com)
+ @author revised by Bart Teeuwisse (bart.teeuwisse@thecodemill.biz)
+ @revision-date April 2002
+
+} {
+ user_id:integer,notnull
+ usca_p:optional
+}
+
+set admin_p [permission::permission_p -object_id [ad_conn package_id] -privilege "admin"]
+
+# This is a "thank you for your order" page displays order summary for
+# the most recently confirmed order for this user
+
+# We need them to be logged in
+
+#set user_id [ad_verify_and_get_user_id]
+if {$user_id == 0} {
+ set return_url "[ad_conn url]"
+ ad_returnredirect "[ad_conn package_url]register?[export_url_vars return_url]"
+ ad_script_abort
+}
+
+# wtem@olywa.net, 2001-03-21
+# it isn't clear to me why we would log the session here
+# or why you would create a new session at this point
+
+# User session tracking
+
+set user_session_id [ec_get_user_session_id]
+ec_create_new_session_if_necessary
+ec_log_user_as_user_id_for_this_session
+
+# Their most recently confirmed order (or the empty string if there is
+# none)
+
+set order_id [db_string get_order_id_info "
+ select order_id
+ from ec_orders
+ where user_id=:user_id
+ and confirmed_date is not null
+ and order_id = (
+ select max(o2.order_id)
+ from ec_orders o2
+ where o2.user_id = $user_id
+ and o2.confirmed_date is not null)" -default ""]
+
+if { [empty_string_p $order_id] } {
+ rp_internal_redirect index
+ ad_stript_abort
+}
+
+set order_summary [ec_order_summary_for_customer $order_id $user_id]
+set context { {Order Confirmation} }
+set ec_system_owner [ec_system_owner]
+
+db_release_unused_handles
+ad_return_template
+
Index: openacs-4/packages/dotlrn-ecommerce/www/ecommerce/thank-you.xql
===================================================================
RCS file: /usr/local/cvsroot/openacs-4/packages/dotlrn-ecommerce/www/ecommerce/thank-you.xql,v
diff -u
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ openacs-4/packages/dotlrn-ecommerce/www/ecommerce/thank-you.xql 23 Jun 2005 12:28:21 -0000 1.1
@@ -0,0 +1,17 @@
+
+
+