Index: openacs-4/packages/ecommerce/www/finalize-order.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/ecommerce/www/finalize-order.tcl,v diff -u -r1.2 -r1.3 --- openacs-4/packages/ecommerce/www/finalize-order.tcl 21 Aug 2001 04:42:27 -0000 1.2 +++ openacs-4/packages/ecommerce/www/finalize-order.tcl 26 May 2002 04:36:50 -0000 1.3 @@ -1,31 +1,34 @@ -# www/ecommerce/finalize-order.tcl ad_page_contract { - this script will: - (1) put this order into the 'confirmed' state - (2) try to authorize the user's credit card info and either - (a) redirect them to a thank you page, or - (b) redirect them to a "please fix your credit card info" page + This script will: + + (1) put this order into the 'confirmed' state + (2) try to authorize the user's credit card info and either + (a) redirect them to a thank you page, or + (b) redirect them to a "please fix your credit card info" + page + @author @creation-date - @cvs-id finalize-order.tcl,v 3.3.6.9 2000/09/22 01:37:30 kevin Exp @author ported by Jerry Asher (jerry@theashergroup.com) @author and Walter McGinnis (wtem@olywa.net) + @author revised by Bart Teeuwisse + @revision-date April 2002 + } { } # If they reload, we don't have to worry about the credit card # authorization code being executed twice because the order has -# already been moved to the 'confirmed' state, which means that -# they will be redirected out of this page. -# We will redirect them to the thank you page which displays the -# order with the most recent confirmation date. -# The only potential problem is that maybe the first time the -# order got to this page it was confirmed but then execution of -# the page stopped before authorization of the order could occur. -# This problem is solved by the scheduled procedure, -# ec_query_for_cybercash_zombies, which will try to authorize -# any 'confirmed' orders over half an hour old. +# already been moved to the 'confirmed' state, which means that they +# will be redirected out of this page. We will redirect them to the +# thank you page which displays the order with the most recent +# confirmation date. The only potential problem is that maybe the +# first time the order got to this page it was confirmed but then +# execution of the page stopped before authorization of the order +# could occur. This problem is solved by the scheduled procedure, +# ec_query_for_payment_zombies, which will try to authorize any +# 'confirmed' orders over half an hour old. ec_redirect_to_https_if_possible_and_necessary @@ -56,22 +59,25 @@ 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 ""] +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] } { - # find their most recently confirmed order + + # Find their most recently confirmed order + set most_recently_confirmed_order [db_string get_mrc_order " - select order_id + 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 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 ""] + and o2.confirmed_date is not null)" -default ""] if { [empty_string_p $most_recently_confirmed_order] } { ad_returnredirect index @@ -81,115 +87,738 @@ template::adp_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. +# Make sure there's something in their shopping cart, otherwise +# redirect them to their shopping cart which will tell them that it's +# empty. -# we may want to make this a redirect to insecure location -if { [db_string get_in_basket_count "select count(*) from ec_items where order_id=:order_id"] == 0 } { +# We may want to make this a redirect to insecure location + +if { [db_string get_in_basket_count " + select count(*) + from ec_items + where order_id = :order_id"] == 0 } { ad_returnredirect shopping-cart template::adp_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"] +# 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 } { ad_returnredirect checkout template::adp_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 +# 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_a_shipping_address "select shipping_address from ec_orders where order_id=:order_id" -default ""] +set address_id [db_string get_a_shipping_address " + select shipping_address + from ec_orders + where order_id=:order_id" -default ""] if { [empty_string_p $address_id] } { - ad_returnredirect checkout - template::adp_abort + + # 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] + return + } } -# 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 +# 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 ""] +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] } { - # we only want price and shipping from this (to determine whether gift_certificate 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]] + # We only want price and shipping from this (to determine whether + # gift_certificate covers cost) - set gift_certificate_balance [db_string get_gc_balance "select ec_gift_certificate_balance(:user_id) from dual"] - + 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 "f" } else { set gift_certificate_covers_cost_p "t" - - ### gilbertw: removed the next three lines - ### the openacs 3.2.5 code does not have the next 2/3 lines - ### instead it uses ec_update_state_to_confirmed 20 lines later - ### which handles the gift certificate amounts - ### if ec_update_state_to_authorized is used, the gift certificate - ### amounts do not get subtracted - # ec_update_state_to_authorized $order_id "authorized_plus_avs" - #ad_returnredirect thank-you - #template::adp_abort } } -set shipping_method [db_string get_shipping_method "select shipping_method from ec_orders where order_id=:order_id" -default ""] - - +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] && (![info exists gift_certificate_covers_cost_p] || $gift_certificate_covers_cost_p == "f")) } { ad_returnredirect checkout-2 template::adp_abort } +# Done with all the checks! -# done with all the checks! - # (1) put this order into the 'confirmed' state db_transaction { - -ec_update_state_to_confirmed $order_id - + ec_update_state_to_confirmed $order_id } -# (2) try to authorize the user's credit card info and either +# (2) Try to authorize the user's credit card info and either # (a) send them email & redirect them to a thank you page, or # (b) redirect them to a "please fix your credit card info" page -set cc_result [ec_creditcard_authorization $order_id] +set applied_certificate_amount [db_string get_applied_certificate_amount " + select ec_order_gift_cert_amount(:order_id)"] +db_1row get_soft_goods_costs " + select coalesce(sum(i.price_charged),0) - coalesce(sum(i.price_refunded),0) as soft_goods_cost, + coalesce(sum(i.price_tax_charged),0) - coalesce(sum(i.price_tax_refunded),0) as soft_goods_tax + from ec_items i, ec_products p + where i.order_id = :order_id + and i.item_state <> 'void' + and i.product_id = p.product_id + and p.no_shipping_avail_p = 't'" +db_1row get_hard_goods_costs " + select coalesce(sum(i.price_charged),0) - coalesce(sum(i.price_refunded),0) as hard_goods_cost, + coalesce(sum(i.price_tax_charged),0) - coalesce(sum(i.shipping_refunded),0) as hard_goods_tax, + coalesce(sum(i.shipping_charged),0) - coalesce(sum(i.shipping_refunded),0) as hard_goods_shipping, + coalesce(sum(i.shipping_tax_charged),0) - coalesce(sum(i.shipping_tax_refunded),0) as hard_goods_shipping_tax + from ec_items i, ec_products p + where i.order_id = :order_id + and i.item_state <> 'void' + and i.product_id = p.product_id + and p.no_shipping_avail_p = 'f'" +set order_shipping [db_string get_order_shipping " + select coalesce(shipping_charged, 0) + from ec_orders + where order_id = :order_id"] +set order_shipping_tax [db_string get_order_shipping_tax " + select ec_tax(0, :order_shipping, :order_id)"] -if { [string equal $cc_result "authorized_plus_avs"] || [string equal $cc_result "authorized_minus_avs"] } { - ec_email_new_order $order_id - ec_update_state_to_authorized $order_id [ec_decode $cc_result "authorized_plus_avs" "t" "f"] -} +# Charge soft goods seperately from hard goods as the hard goods +# transaction will not settled until the goods are shipped while soft +# goods can be settled right away. -# wtem@olywa.net, 2001-03-21 -# replaced string1 == string2 with [string equal string1 string2] -if { [string equal $cc_result "authorized_plus_avs"] || [string equal $cc_result "authorized_minus_avs"] || [string equal $cc_result "no_recommendation"] } { - ad_returnredirect thank-you - template::adp_abort -} elseif { [string equal $cc_result "failed_authorization"] } { - # updates everything that needs to be updated if a confirmed offer fails - ec_update_state_to_in_basket $order_id +if {$hard_goods_cost > 0} { - ad_returnredirect credit-card-correction - template::adp_abort + # The order contains hard goods that come at a cost. + + if {$soft_goods_cost > 0} { + + # The order contains both hard and soft goods that come at a + # cost. + + if {$applied_certificate_amount >= [expr $soft_goods_cost + $soft_goods_tax]} { + + # The applied certificates cover the cost of the soft + # goods. + + if {[expr $applied_certificate_amount - $soft_goods_cost - $soft_goods_tax] >= [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 soft + # goods as well as the hard goods. 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 thank-you + + } else { + + # The applied certificates cover the cost of the soft + # goods but not 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 thank-you + template::adp_abort + } elseif { [string equal $result "failed_authorization"] } { + + # Updates everything that needs to be updated if a + # confirmed order fails + + ec_update_state_to_in_basket $order_id + + ad_returnredirect credit-card-correction + template::adp_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" " +

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 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 thank-you + + } 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 + + ad_returnredirect credit-card-correction + template::adp_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" " +

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 thank-you + + } 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 + ad_returnredirect 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" " +

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 + + ad_returnredirect credit-card-correction + template::adp_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" " +

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 thank-you + + } 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 thank-you + template::adp_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 + + ad_returnredirect credit-card-correction + template::adp_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" " +

Sorry

+

There has been an error in the processing of your credit card information. + Please contact [ec_system_owner] to report the error.

" + } + } + } } else { - # Then cc_result is probably "invalid_input". - # This should never occur - ns_log Notice "Order $order_id received a cc_result of $cc_result" - ad_return_error "Sorry" " -

Sorry

-There has been an error in the processing of your credit card information. Please contact
[ec_system_owner]
to report the error. -[ad_footer] -" -} + + # 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 thank-you + + } 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_capture_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 thank-you + } + + 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 + + ad_returnredirect credit-card-correction + template::adp_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" " +

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 thank-you + } +}