# 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 "
  • You forgot to enter your credit card number\n" } else { # credit card came fresh from consumer, take out the spaces regsub -all " " $card_number "" card_number # take out the dashes also # need the weird "--" to separate switches from the pattern regsub -all -- {-} $card_number "" card_number } if { ![info exists email] || [string compare $email ""] == 0 } { incr exception_count append exception_text "
  • You forgot to enter your email address\n" } if { [info exists email] && [string compare $email ""] != 0 && ![philg_email_valid_p $email] } { incr exception_count append exception_text "
  • Your email address doesn't look right to us. We need your full Internet address, something like one of the following: " } if { ![info exists last_name] || [string compare $last_name ""] == 0 } { incr exception_count append exception_text "
  • You forgot to enter your last name\n" } if { ![info exists phone_number] || [string compare $phone_number ""] == 0 } { incr exception_count append exception_text "
  • You forgot to enter your telephone number\n" } if { (![info exists card_exp1] || [string compare $card_exp1 ""] == 0) && (![info exists card_exp2] || [string compare $card_exp2 ""] == 0) } { incr exception_count append exception_text "
  • You forgot to enter your credit card expiration date\n" } elseif { ![regexp {[0-9][0-9]} $card_exp1] || ![regexp {[0-9][0-9]} $card_exp2] } { incr exception_count append exception_text "
  • Credit card expiration date needs to be in the form MM/YY\n" } if { ![info exists line1] || [string compare $line1 ""] == 0 } { incr exception_count append exception_text "
  • You forgot to enter your address\n" } if { ![info exists city] || [string compare $city ""] == 0 } { incr exception_count append exception_text "
  • You forgot to enter your city\n" } if { ![info exists postal_code] || [string compare $postal_code ""] == 0 } { incr exception_count append exception_text "
  • You forgot to enter your postal code\n" } set selection [ns_db 0or1row $db "select short_name, currency, price, soft_good_p, display_after from sh_products where product_id = $product_id"] if { $selection == "" } { incr exception_count append exception_text "
  • We couldn't find this product in our database." } else { # got a row back from the db # set some Tcl vars for use below (bleah) set_variables_after_query } if { $exception_count != 0 } { if { $exception_count == 1 } { set problem_string "a problem" set please_correct "it" } else { set problem_string "some problems" set please_correct "them" } ns_return 200 text/html "[sh_header "Problem with your Order"]

    Problem with your order

    on [sh_system_linked_name]
    We had $problem_string processing your order: Please back up using your browser, correct $please_correct, and resubmit your order.

    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"]

    Order Already Placed

    in [sh_system_linked_name]
    You've probably hit submit twice from the same form. We are already in possession of an order with id # $order_id (placed $n_seconds seconds ago) and it is being processed. You can check on the status of this order if you like. [sh_footer]" } else { # Oracle choked on something else (vomit?) ns_return 500 text/html "[sh_header "Database Error"]

    Database Error

    in [sh_system_linked_name]
    Our database choked on your order:
    $errmsg
    [sh_footer]" } return } # we stuffed the row into Oracle, now let's talk to CyberCash ReturnHeaders ns_write "[sh_header "Order Placed"]

    Order Placed

    with [sh_system_linked_name]
    Your order has been placed in our database. Now we're going to try to connect to CyberCash to authorize your credit card.

    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 "

    Credit Card Correction Needed

    CyberCash has noted the following problem with your submission:
    $message_for_user
    Please 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).
    [export_form_vars order_id product_id first_names last_name email phone_number line1 line2 city state postal_code country_code]

    Credit Card Info

    Card Number
    Expiration Date (MM/YY) /
    Name on credit card
    Billing Zip Code (5 digits)
    " # 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] "Order failed at [sh_system_url]" "$email attempted to place an order for $short_name \n\nat [sh_system_url] \n\nbut got hit with \"$message_for_user\"" } errmsg] { ns_log Notice "failed sending email to system owner: $errmsg" } } else { # Order successful # CyberCash gave result "avs verified" as defined in defs.tcl if {$avs_verified_p == 1} { set new_state "authorized_plus_avs" } else { set new_state "authorized_minus_avs" } ns_db dml $db "update sh_orders set order_state = '$new_state', authorized_date = sysdate, 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" ns_write "

    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] "