# if you want a variety of debugging crud written to the AOLserver # error log (useful for getting CyberCash merchant account up and # running), set this to 1 set log_cybercash_results_p 1 set display_cybercash_results_p 0 # processes an order from order.tcl (though basically we expect to get # it from a static HTML form somewhere else on the publisher's site) set_the_usual_form_variables # an unknown variety of crud, but presumably at least # order_id, product_id, first_names, last_name, email, card_number # card_exp, name_on_card, # billing_zip_code, line1, line2, city, state, postal_code, country_code # phone_number set db [sh_gethandle] # check for errors first set exception_count 0 set exception_text "" if { ![info exists card_number] || [string compare $card_number ""] == 0 } { incr exception_count append exception_text "
- Joe.Smith@att.com
- student73@cs.stateu.edu
- francois@unique.fr
"
}
if { ![info exists last_name] || [string compare $last_name ""] == 0 } {
incr exception_count
append exception_text "Thank you. [sh_footer]" return } # there is at least some integrity to this order set insert_sql "insert into sh_orders (order_id, product_id, ip_address, order_state, confirmed_date, first_names, last_name, email, name_on_card, billing_zip_code, price_charged, currency, phone_number, line1, line2, city, state, postal_code, country_code) values ($order_id, $product_id, '[DoubleApos [ns_conn peeraddr]]', 'confirmed', sysdate, '$QQfirst_names', '$QQlast_name', '$QQemail', '$QQname_on_card', '$QQbilling_zip_code', '$price', '$currency', '$QQphone_number', '$QQline1','$QQline2', '$QQcity', '$QQstate', '$QQpostal_code','$country_code')" if [catch { ns_db dml $db $insert_sql } errmsg] { # Oracle choked set selection [ns_db 0or1row $db "select round((sysdate-confirmed_date)*86400) as n_seconds from sh_orders where order_id = $order_id"] if { $selection != "" } { # there is already a row in the database with this order id; # presumably the user hit submit twice by mistake set_variables_after_query ns_return 200 text/html "[sh_header "Order Already Placed"]
$errmsg[sh_footer]" } return } # we stuffed the row into Oracle, now let's talk to CyberCash ReturnHeaders ns_write "[sh_header "Order Placed"]
Connecting...
" set args [ns_set new] set cc_output [ns_set new] set card_exp "$card_exp1/$card_exp2" ns_set put $args "amount" "$currency $price" ns_set put $args "order-id" $order_id ns_set put $args "card-number" $card_number ns_set put $args "card-name" $name_on_card ns_set put $args "card-zip" $billing_zip_code ns_set put $args "card-country" "USA" ns_set put $args "card-exp" $card_exp cc_send_to_server_21 "mauthonly" $args $cc_output # Now there's a bunch of notices, logging, retry for failed authorization, etc. # that only take place if CyberCash actually returns something. If not, the # customer will be given a message after timeout (which we have set to 30 sec) # saying that we will query CyberCash later to see if the order got through. if { [ns_set size $cc_output] != 0 } { set cybercash_succeeded_p [regexp {success} [ns_set get $cc_output "MStatus"]] set avs_verified_p [sh_avs_acceptable_p [ns_set get $cc_output "avs-code"]] if $display_cybercash_results_p { ns_write "The value of cybercash_succeeded_p is $cybercash_succeeded_p" ns_write "
[NsSettoTclString $cc_output]" ns_write "avs_verified_p: $avs_verified_p
" } if $log_cybercash_results_p { ns_log Notice "CyberCash_results: [NsSettoTclString $cc_output]" } # Retry if MStatus is failure-q-or-cancel if { [ns_set get $cc_output "MStatus"] == "failure-q-or-cancel" } { ns_log Notice "Retrying failure-q-or-cancel order # $order_id" ns_write "
CyberCash has reported that the transaction has failed due to a communications failure. We will retry the transaction once..." set cc_output [ns_set new] cc_send_to_server_21 "retry" $args $cc_output set cybercash_succeeded_p [regexp {success} [ns_set get $cc_output "MStatus"]] set avs_verified_p [sh_avs_acceptable_p [ns_set get $cc_output "avs-code"]] if $display_cybercash_results_p { ns_write "The value of cybercash_succeeded_p is $cybercash_succeeded_p" ns_write "
[NsSettoTclString $cc_output]" ns_write "avs_verified_p: $avs_verified_p
" } if $log_cybercash_results_p { ns_log Notice "CyberCash_results: [NsSettoTclString $cc_output]" } } if {$cybercash_succeeded_p == 0} { # Catch cybercash failures that can be corrected & ask for correction # let's see if we can't prettify the error message if { [ns_set ifind $cc_output "MErrMsg"] != -1 } { # there is an error message from CyberCash set raw_error_message [ns_set get $cc_output "MErrMsg"] if { [regexp {Expiration date has passed} $raw_error_message] } { set message_for_user "Expiration date on your credit card has passed" } elseif { [regexp {fails LUHN-10 check} $raw_error_message] } { set message_for_user "The credit card number was invalid; probably you made a typo in entering it." } else { set message_for_user $raw_error_message } } else { # we can't figure out what went wrong; no error message set message_for_user "We didn't get back an explanation from CyberCash. The status of the transaction was \"[ns_set get $cc_output "Mstatus"]\"" } # Update the problems table ns_db dml $db "insert into sh_problems_log (problem_id, order_id, problem_date, txn_type, txn_status, error_message) values (sh_problem_id_sequence.nextval, $order_id, sysdate, 'auth', '[DoubleApos [ns_set get $cc_output "MStatus"]]', '[DoubleApos [ns_set get $cc_output "MErrMsg"]]')" # Update the orders table ns_db dml $db "update sh_orders set order_state = 'failed_authorization', cc_auth_status = '[DoubleApos [ns_set get $cc_output "MStatus"]]', cc_auth_txn_id = '[DoubleApos [ns_set get $cc_output "merch-txn"]]', cc_auth_errloc = '[DoubleApos [ns_set get $cc_output "MErrLoc"]]', cc_auth_errmsg = '[DoubleApos [ns_set get $cc_output "MErrMsg"]]', cc_auth_aux_msg = '[DoubleApos [ns_set get $cc_output "aux-msg"]]', cc_auth_auth_code = '[DoubleApos [ns_set get $cc_output "auth-code"]]', cc_auth_action_code = '[DoubleApos [ns_set get $cc_output "action-code"]]', cc_auth_avs_code = '[DoubleApos [ns_set get $cc_output "avs-code"]]', cc_auth_ref_code = '[DoubleApos [ns_set get $cc_output "ref-code"]]' where order_id=$order_id" #get a new order_id, and let them fix their credit card info set order_id [database_to_tcl_string $db "select sh_order_id_sequence.nextval from dual"] ns_write "
$message_for_userPlease check the information in the form below and resubmit (if the error is related to a CyberCash timeout as opposed to invalid credit card information, please wait 15 minutes and then resubmit below).
Credit card authorized. Thank you for your order!
Your credit card statement will show a charge of $currency $price from \"[sh_merchant_account_name]\".
" # This is the HTML (specific to the product) that is displayed after # a successful purchase. ns_write "$display_after" # send email to the customer set email_subject "Thank you for ordering from [sh_system_name]" set email_body "Thank you for ordering $short_name from [sh_system_name] at [sh_system_url]. Your credit card statement will show a charge of $currency $price from \"[sh_merchant_account_name]\"." if [catch { ns_sendmail $email [sh_from_email] $email_subject $email_body } errmsg] { ns_log Notice "failed sending confirmation email to customer: $errmsg" } # send email to the shoppe owner (high-volume shoppes will want to comment this out) if [catch { ns_sendmail [sh_system_owner] [sh_from_email] "New order at [sh_system_url]" "$email placed an order for $short_name \n\nat [sh_system_url]" } errmsg] { ns_log Notice "failed sending email to system owner: $errmsg" } # If it's a soft good, we also want to update the order_state to "shipped" # (and update the shipped_date) and mark the order for capture if { $soft_good_p == "t" } { ns_db dml $db "update sh_orders set order_state='shipped', shipped_date=sysdate where order_id=$order_id" set args [ns_set new] set cc_output [ns_set new] ns_set put $args "amount" "$currency $price" ns_set put $args "order-id" $order_id cc_send_to_server_21 "postauth" $args $cc_output # Check the size of cc_output to see if we got through to CyberCash. if { [ns_set size $cc_output] != 0 } { # If unsuccessful, update problems table. If successful # set postauth_date. if { [regexp {success} [ns_set get $cc_output "MStatus"]] } { ns_db dml $db "update sh_orders set postauth_date=sysdate where order_id=$order_id" } else { ns_db dml $db "insert into sh_problems_log (problem_id, order_id, problem_date, txn_type, txn_status, error_message) values (sh_problem_id_sequence.nextval, $order_id, sysdate, 'marked', '[DoubleApos [ns_set get $cc_output "MStatus"]]', '[DoubleApos [ns_set get $cc_output "MErrMsg"]]')" } # Regardless of success of postauth, update the sh_orders table ns_db dml $db "update sh_orders set cc_post_status = '[DoubleApos [ns_set get $cc_output "MStatus"]]', cc_post_txn_id = '[DoubleApos [ns_set get $cc_output "merch-txn"]]', cc_post_errloc = '[DoubleApos [ns_set get $cc_output "MErrLoc"]]', cc_post_errmsg = '[DoubleApos [ns_set get $cc_output "MErrMsg"]]', cc_post_aux_msg = '[DoubleApos [ns_set get $cc_output "aux-msg"]]', cc_post_auth_code = '[DoubleApos [ns_set get $cc_output "auth-code"]]', cc_post_action_code = '[DoubleApos [ns_set get $cc_output "action-code"]]', cc_post_avs_code = '[DoubleApos [ns_set get $cc_output "avs-code"]]', cc_post_ref_code = '[DoubleApos [ns_set get $cc_output "ref-code"]]' where order_id=$order_id" } else { # no response from CyberCash when trying to postauth ns_db dml $db "insert into sh_problems_log (problem_id, order_id, problem_date, txn_type, error_message) values (sh_problem_id_sequence.nextval, $order_id, sysdate, 'marked', 'CyberCash gave no response')" } } } } else { # no response from CyberCash ns_write " CyberCash didn't give us a confirmation of your order. We will automatically query CyberCash within the next 1.5 hours to see if they processed your transaction, and we will email you with the results. " ns_db dml $db "insert into sh_problems_log (problem_id, order_id, problem_date, txn_type, error_message) values (sh_problem_id_sequence.nextval, $order_id, sysdate, 'auth', 'CyberCash gave no response')" } ns_write " [sh_footer] "