Index: openacs-4/packages/authorize-gateway/authorize-gateway.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/authorize-gateway.info,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/authorize-gateway.info 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,56 @@ + + + + + Authorize.net Gateway + Authorize.net Gateways + f + t + + + + oracle + postgresql + + Bart Teeuwisse + Authorize.net payment gateway + 2002-05-13 + Payment gateway to Authorize.net. An account with Authorize.net and a merchant account are required. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Index: openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-create.sql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,16 @@ +create table authorize_gateway_result_log ( + transaction_id varchar(20) not null, + txn_attempted_type varchar(18), + txn_attempted_time datetime, + response varchar(300), + response_code varchar(1), + response_reason_code varchar(2), + response_reason_text varchar(100), + auth_code varchar(6), + avs_code varchar(3), + amount numeric not null +); + +create index authorize_gateway_result_log_transaction_id on authorize_gateway_result_log(transaction_id); + +\i authorize-gateway-sc-create.sql \ No newline at end of file Index: openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-drop.sql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,3 @@ +drop table authorize_gateway_result_log; + +\i authorize-gateway-sc-drop.sql Index: openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-sc-create.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-sc-create.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-sc-create.sql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,57 @@ +-- This is an Authorize.net implementation of the PaymentGateway +-- service contract + +select acs_sc_impl__new( + 'PaymentGateway', -- impl_contract_name + 'authorize-gateway', -- impl_name + 'authorize-gateway' -- impl_owner_name +); + + +select acs_sc_impl_alias__new( + 'PaymentGateway', -- impl_contract_name + 'authorize-gateway', -- impl_name + 'Authorize', -- impl_operation_name + 'authorize_gateway.authorize', -- impl_alias + 'TCL' -- impl_pl +); + +select acs_sc_impl_alias__new( + 'PaymentGateway', -- impl_contract_name + 'authorize-gateway', -- impl_name + 'ChargeCard', -- impl_operation_name + 'authorize_gateway.chargecard', -- impl_alias + 'TCL' -- impl_pl +); + +select acs_sc_impl_alias__new( + 'PaymentGateway', -- impl_contract_name + 'authorize-gateway', -- impl_name + 'Return', -- impl_operation_name + 'authorize_gateway.return', -- impl_alias + 'TCL' -- impl_pl +); + +select acs_sc_impl_alias__new( + 'PaymentGateway', -- impl_contract_name + 'authorize-gateway', -- impl_name + 'Void', -- impl_operation_name + 'authorize_gateway.void', -- impl_alias + 'TCL' -- impl_pl +); + +select acs_sc_impl_alias__new( + 'PaymentGateway', -- impl_contract_name + 'authorize-gateway', -- impl_name + 'Info', -- impl_operation_name + 'authorize_gateway.info', -- impl_alias + 'TCL' -- impl_pl +); + +-- Add the binding + +select acs_sc_binding__new ( + 'PaymentGateway', + 'authorize-gateway' +); + Index: openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-sc-drop.sql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-sc-drop.sql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/sql/postgresql/authorize-gateway-sc-drop.sql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,45 @@ +select acs_sc_binding__delete( + 'PaymentGateway', + 'authorize-gateway' +); + +select acs_sc_impl_alias__delete( + 'PaymentGateway', + 'authorize-gateway', + 'Authorize' +); + +select acs_sc_impl_alias__delete( + 'PaymentGateway', + 'authorize-gateway', + 'ChargeCard' +); + +select acs_sc_impl_alias__delete( + 'PaymentGateway', + 'authorize-gateway', + 'Return' +); + +select acs_sc_impl_alias__delete( + 'PaymentGateway', + 'authorize-gateway', + 'Void' +); + +select acs_sc_impl_alias__delete( + 'PaymentGateway', + 'authorize-gateway', + 'Info' +); + +select acs_sc_binding__delete( + 'PaymentGateway', + 'authorize-gateway' +); + +select acs_sc_impl__delete( + 'PaymentGateway', + 'authorize-gateway' +); + Index: openacs-4/packages/authorize-gateway/tcl/authorize-gateway-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/tcl/authorize-gateway-procs.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/tcl/authorize-gateway-procs.tcl 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,829 @@ +ad_library { + + Procedures to implement Authorize.net credit card transactions. + + @author Bart Teeuwisse + @creation-date March 2002 +} + +ad_proc -private authorize_gateway.authorize { + transaction_id + amount + card_type + card_number + card_exp_month + card_exp_year + card_name + billing_street + billing_city + billing_state + billing_zip + billing_country +} { + Connect to Authorize.net to authorize a transaction for the amount + given on the card given. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + # 1. Send transaction off to gateway + + set test_request [authorize_gateway.decode_test_request] + set field_seperator [ad_parameter field_seperator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_seperator]] + set field_encapsulator [ad_parameter field_encapsulator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_encapsulator]] + set referer_url [ad_parameter referer_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] referer_url]] + + # Add the Referer to the headers passed on to Authorize.net + + set header [ns_set new] + ns_set put $header Referer $referer_url + + # Compile the URL for the GET communication with Authorize.net + + # Basic secure URL and account info. + + set full_url "[ad_parameter authorize_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_url]]?x_Login=[ns_urlencode [ad_parameter authorize_login -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_login]]]&x_Password=[ns_urlencode [ad_parameter authorize_password -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_password]]]" + + # Add necessary ADC (Authorize.net Direct Connect) info such as the delimiting character. + + append full_url "&x_ADC_URL=False&x_ADC_Delim_Data=True&x_ADC_Delim_Character=[ns_urlencode $field_seperator]" + + # Set the test request flag to indicate trial communication or a real live transaction. + + append full_url "&x_Test_Request=[ns_urlencode $test_request]" + + # Set the transaction type to AUTHORIZE ONLY and set the invoice + # number to the transaction id paramater. This is a bit confusing + # as the transaction id passed to this procedure should not be + # mistaken for the transaction id that Authorize.net will generate + # and return. The Authorize.net transaction id will be store in + # the response_transaction_id. Use the response_transaction_id to + # complete the transaction with a POST_AUTH operation. + + append full_url "&x_Type=AUTH_ONLY&x_Amount=[ns_urlencode [format "%0.2f" $amount]]&x_Invoice_Num=$transaction_id&x_Description=[ns_urlencode [ad_parameter description -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] description]]]" + + # Set the credit card information. + + append full_url "&x_Card_Num=[ns_urlencode $card_number]&x_Exp_Date=[ns_urlencode ${card_exp_month}/${card_exp_year}]&x_Last_Name=[ns_urlencode $card_name]" + + # Set the billing information. The information will be used by + # Authorize.net to run an AVS check. + + append full_url "&x_Address=[ns_urlencode $billing_street]&x_City=[ns_urlencode $billing_city]&x_Zip=[ns_urlencode $billing_zip]&x_State=[ns_urlencode $billing_state]&x_Country=[ns_urlencode $billing_country]" + + # Contact Authorize.net and receive the character delimited + # response. Timeout after 30 seconds, don't allow any redirects + # and pass a set of custom headers to Authorize.net. + + if {[catch {set response [ns_httpsget $full_url 30 0 $header]} error_message]} { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "AUTH_ONLY" $error_message 3 "" $error_message "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Transaction $transaction_id failed, could not contact Authorize.net: $error_message" + set return(transaction_id) $transaction_id + return [array get return] + } else { + + # 2. Insert into log table + + # Decode the response from Authorize.net. Not all fields are + # of interest. See the Authorize.net documentation + # (https://secure.authorize.net/docs/response.pml) + # for a complete list of response codes. + + set response_list "\{[string map [list $field_encapsulator$field_seperator$field_encapsulator "\} \{" $field_encapsulator {}] $response]\}" + + # Check that the response from Authorize.net is a legimate ADC + # response. When Authorize.net has problems the response is + # not a character delimited list but an HTML page. An ADC + # response has certainly 38 or more elements. Future + # versions might return more elements. + + if { [llength $response_list] < 38 } { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "AUTH_ONLY" $response 3 "" \ + "Authorize.net must be down, the response was not a character delimited list" "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Authorize.net must be down, the response was not a character delimited list" + set return(transaction_id) $transaction_id + return [array get return] + } else { + set response_code [lindex $response_list 0] + set response_reason_code [lindex $response_list 2] + set response_reason_text [lindex $response_list 3] + set response_auth_code [lindex $response_list 4] + set response_avs_code [lindex $response_list 5] + set response_transaction_id [lindex $response_list 6] + set response_md5_hash [lindex $response_list 37] + authorize_gateway.log_results $response_transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "AUTH_ONLY" \ + $response $response_code $response_reason_code $response_reason_text $response_auth_code $response_avs_code $amount + + # 3. Return result + + return [authorize_gateway.decode_response $transaction_id $response_transaction_id $response_code $response_reason_code $response_reason_text \ + $response_md5_hash $amount] + } + } +} + +ad_proc -public authorize_gateway.chargecard { + transaction_id + amount + card_type + card_number + card_exp_month + card_exp_year + card_name + billing_street + billing_city + billing_state + billing_zip + billing_country +} { + ChargeCard is a wrapper so we can present a consistent interface to + the caller. It will just pass on it's parameters to + authorize_gateway.postauth or authorize_gateway.authcapture, + whichever is appropriate for the implementation at hand. + + PostAuth is used when there is a successful authorize transaction in + the authorize_gateway_result_log for transaction_id. AuthCapture will + be used if there is no prior authorize transaction in the log. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + + # 1. Check for the existence of a prior auth_only for the transaction_id. + + if {[db_0or1row select_auth_only " + select transaction_id, auth_code + from authorize_gateway_result_log + where txn_attempted_type='AUTH_ONLY' + and response_code='1' + and transaction_id=:transaction_id"]} { + + # 2a. The transaction has been authorized, now mark the transaction for settlement. + + return [authorize_gateway.postauth $transaction_id $auth_code $card_number $card_exp_month $card_exp_year $amount] + + } else { + + # 2b. This is a new transaction which will be authorized and automatically marked for settlement. + + return [authorize_gateway.authcapture $transaction_id $amount $card_type $card_number $card_exp_month $card_exp_year \ + $card_name $billing_street $billing_city $billing_state $billing_zip $billing_country] + } +} + +ad_proc -public authorize_gateway.return { + transaction_id + amount + card_type + card_number + card_exp_month + card_exp_year + card_name + billing_street + billing_city + billing_state + billing_zip + billing_country +} { + Connect to Authorize.net to refund the amount given to the card given. + The transaction id needs to reference a settled transaction performed + with the same card. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + + # 1. Send transaction off to gateway + + set test_request [authorize_gateway.decode_test_request] + set field_seperator [ad_parameter field_seperator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_seperator]] + set field_encapsulator [ad_parameter field_encapsulator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_encapsulator]] + set referer_url [ad_parameter referer_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] referer_url]] + + # Add the Referer to the headers passed on to Authorize.net + + set header [ns_set new] + ns_set put $header Referer $referer_url + + # Compile the URL for the GET communication with Authorize.net + + # Basic secure URL and account info. + + set full_url "[ad_parameter authorize_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_url]]?x_Login=[ns_urlencode [ad_parameter authorize_login -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_login]]]&x_Password=[ns_urlencode [ad_parameter authorize_password -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_password]]]" + + # Add necessary ADC (Authorize.net Direct Connect) info such as the delimiting character. + + append full_url "&x_ADC_URL=False&x_ADC_Delim_Data=True&x_ADC_Delim_Character=[ns_urlencode $field_seperator]" + + # Set the test request flag to indicate trial communication or a real live transaction. + + append full_url "&x_Test_Request=[ns_urlencode $test_request]" + + # Set the transaction type to CREDIT and the transaction id. + + append full_url "&x_Type=CREDIT&x_Amount=[ns_urlencode [format "%0.2f" $amount]]&x_Trans_ID=$transaction_id" + + # Set the credit card information. + + append full_url "&x_Card_Num=[ns_urlencode $card_number]&x_Exp_Date=[ns_urlencode ${card_exp_month}/${card_exp_year}]&x_Last_Name=[ns_urlencode $card_name]" + + # Contact Authorize.net and receive the character delimited + # response. Timeout after 30 seconds, don't allow any redirects + # and pass a set of custom headers to Authorize.net. + + if {[catch {set response [ns_httpsget $full_url 30 0 $header]} error_message]} { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "CREDIT" $error_message 3 "" $error_message "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Transaction $transaction_id failed, could not contact Authorize.net: $error_message" + set return(transaction_id) $transaction_id + return [array get return] + } else { + + # 3. Insert into log table + + # Decode the response from Authorize.net. Not all fields are + # of interest. See the Authorize.net documentation + # (https://secure.authorize.net/docs/response.pml) + # for a complete list of response codes. + + set response_list "\{[string map [list $field_encapsulator$field_seperator$field_encapsulator "\} \{" $field_encapsulator {}] $response]\}" + + # Check that the response from Authorize.net is a legimate ADC + # response. When Authorize.net has problems the response is + # not a character delimited list but an HTML page. An ADC + # response has certainly 38 or more elements. Future + # versions might return more elements. + + if { [llength $response_list] < 38 } { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "CREDIT" $response 3 "" \ + "Authorize.net must be down, the response was not a character delimited list" "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Authorize.net must be down, the response was not a character delimited list" + set return(transaction_id) $transaction_id + return [array get return] + } else { + set response_code [lindex $response_list 0] + set response_reason_code [lindex $response_list 2] + set response_reason_text [lindex $response_list 3] + set response_auth_code [lindex $response_list 4] + set response_avs_code [lindex $response_list 5] + set response_transaction_id [lindex $response_list 6] + set response_md5_hash [lindex $response_list 37] + authorize_gateway.log_results $response_transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "CREDIT" \ + $response $response_code $response_reason_code $response_reason_text $response_auth_code $response_avs_code $amount + + # 4. Return result + + return [authorize_gateway.decode_response $transaction_id $response_transaction_id $response_code $response_reason_code $response_reason_text \ + $response_md5_hash $amount] + } + } +} + +ad_proc -public authorize_gateway.void { + transaction_id + amount + card_type + card_number + card_exp_month + card_exp_year + card_name + billing_street + billing_city + billing_state + billing_zip + billing_country +} { + Connect to Authorize.net to void the transaction with transaction_id. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + # 1. Send transaction off to gateway + + set test_request [authorize_gateway.decode_test_request] + set field_seperator [ad_parameter field_seperator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_seperator]] + set field_encapsulator [ad_parameter field_encapsulator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_encapsulator]] + set referer_url [ad_parameter referer_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] referer_url]] + + # Add the Referer to the headers passed on to Authorize.net + + set header [ns_set new] + ns_set put $header Referer $referer_url + + # Compile the URL for the GET communication with Authorize.net + + # Basic secure URL and account info. + + set full_url "[ad_parameter "authorize_url"]?x_Login=[ns_urlencode [ad_parameter "authorize_login"]]&x_Password=[ns_urlencode [ad_parameter "authorize_password"]]" + + # Add necessary ADC (Authorize.net Direct Connect) info such as the delimiting character. + + append full_url "&x_ADC_URL=False&x_ADC_Delim_Data=True&x_ADC_Delim_Character=[ns_urlencode field_seperator]" + + # Set the test request flag to indicate trial communication or a real live transaction. + + append full_url "&x_Test_Request=[ns_urlencode $test_request]" + + # Set the transaction type to VOID + + append full_url "&x_Type=VOID&x_Amount=[ns_urlencode [format "%0.2f" $amount]]&x_Invoice_Num=$transaction_id" + + # Set the credit card information. + + append full_url "&x_Card_Num=[ns_urlencode $card_number]&x_Exp_Date=[ns_urlencode ${card_exp_month}/${card_exp_year}]&x_Last_Name=[ns_urlencode $card_name]" + + # Contact Authorize.net and receive the character delimited + # response. Timeout after 30 seconds, don't allow any redirects + # and pass a set of custom headers to Authorize.net. + + if {[catch {set response [ns_httpsget $full_url 30 0 $header]} error_message]} { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "VOID" $error_message 3 "" $error_message "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Transaction $transaction_id failed, could not contact Authorize.net: $error_message" + set return(transaction_id) $transaction_id + return [array get return] + } else { + + # 2. Insert into log table + + # Decode the response from Authorize.net. Not all fields are + # of interest. See the Authorize.net documentation + # (https://secure.authorize.net/docs/response.pml) + # for a complete list of response codes. + + set response_list "\{[string map [list $field_encapsulator$field_seperator$field_encapsulator "\} \{" $field_encapsulator {}] $response]\}" + + # Check that the response from Authorize.net is a legimate ADC + # response. When Authorize.net has problems the response is + # not a character delimited list but an HTML page. An ADC + # response has certainly 38 or more elements. Future + # versions might return more elements. + + if { [llength $response_list] < 38 } { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "VOID" $response 3 "" \ + "Authorize.net must be down, the response was not a character delimited list" "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Authorize.net must be down, the response was not a character delimited list" + set return(transaction_id) $transaction_id + return [array get return] + } else { + set response_code [lindex $response_list 0] + set response_reason_code [lindex $response_list 2] + set response_reason_text [lindex $response_list 3] + set response_auth_code [lindex $response_list 4] + set response_avs_code [lindex $response_list 5] + set response_transaction_id [lindex $response_list 6] + set response_md5_hash [lindex $response_list 37] + authorize_gateway.log_results $response_transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "VOID" \ + $response $response_code $response_reason_code $response_reason_text $response_auth_code $response_avs_code $amount + + # 3. Return result + + return [authorize_gateway.decode_response $transaction_id $response_transaction_id $response_code $response_reason_code $response_reason_text \ + $response_md5_hash $amount] + } + } +} + +ad_proc -public authorize_gateway.info { +} { + Return information about Authorize.net implementation of the + payment service contract. Returns the package_key, version, package name + cards accepted and a list of return codes. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + + array set info [list \ + package_key authorize-gateway \ + version [db_string get_package_version " + select version_name + from apm_package_versions + where enabled_p = 't' + and package_key = 'authorize-gateway'"] \ + package_name [db_string get_package_name " + select instance_name + from apm_packages p, apm_package_versions v + where p.package_key = v.package_key + and v.enabled_p = 't' + and p.package_key = 'authorize-gateway'"] \ + cards_accepted [ad_parameter CreditCardsAccepted -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] CreditCardsAccepted]] \ + success [nsv_get payment_gateway_return_codes success] \ + failure [nsv_get payment_gateway_return_codes failure] \ + retry [nsv_get payment_gateway_return_codes retry] \ + not_supported [nsv_get payment_gateway_return_codes not_supported] \ + not_implemented [nsv_get payment_gateway_return_codes not_implemented]] + return [array get info] +} + +# These stubs aren't exposed via the API - they are called only by ChargeCard. + +ad_proc -private authorize_gateway.postauth { + transaction_id + auth_code + card_number + card_exp_month + card_exp_year + amount +} { + Connect to Authorize.net to PRIOR_AUTH_CAPTURE the transaction with transaction id. + The transaction needs to have been AUTH_ONLY before calling this procedure. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + # 1. Send transaction off to gateway + + set test_request [authorize_gateway.decode_test_request] + set field_seperator [ad_parameter field_seperator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_seperator]] + set field_encapsulator [ad_parameter field_encapsulator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_encapsulator]] + set referer_url [ad_parameter referer_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] referer_url]] + + # Add the Referer to the headers passed on to Authorize.net + + set header [ns_set new] + ns_set put $header Referer $referer_url + + # Compile the URL for the GET communication with Authorize.net + + # Basic secure URL and account info. + + set full_url "[ad_parameter authorize_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_url]]?x_Login=[ns_urlencode [ad_parameter authorize_login -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_login]]]&x_Password=[ns_urlencode [ad_parameter authorize_password -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_password]]]" + + # Add necessary ADC (Authorize.net Direct Connect) info such as the delimiting character. + + append full_url "&x_ADC_URL=False&x_ADC_Delim_Data=True&x_ADC_Delim_Character=[ns_urlencode $field_seperator]" + + # Set the test request flag to indicate trial communication or a real live transaction. + + append full_url "&x_Test_Request=[ns_urlencode $test_request]" + + # Set the transaction type to PRIOR_AUTH_CAPTURE, the transaction_id + # to the id of the transaction that has been authorized and the + # auth_code to the authorization code of that transaction. + + append full_url "&x_Type=PRIOR_AUTH_CAPTURE&x_Amount=[ns_urlencode [format "%0.2f" $amount]]&x_Trans_ID=$transaction_id&x_Auth_Code=$auth_code" + + # Set the credit card information. + + append full_url "&x_Card_Num=[ns_urlencode $card_number]&x_Exp_Date=[ns_urlencode ${card_exp_month}/${card_exp_year}]" + + # Contact Authorize.net and receive the character delimited + # response. Timeout after 30 seconds, don't allow any redirects + # and pass a set of custom headers to Authorize.net. + + if {[catch {set response [ns_httpsget $full_url 30 0 $header]} error_message]} { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "PRIOR_AUTH_CAPTURE" $error_message 3 "" \ + $error_message "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Transaction $transaction_id failed, could not contact Authorize.net: $error_message" + set return(transaction_id) $transaction_id + return [array get return] + } else { + + # 2. Insert into log table + + # Decode the response from Authorize.net. Not all fields are + # of interest. See the Authorize.net documentation + # (https://secure.authorize.net/docs/response.pml) + # for a complete list of response codes. + + set response_list "\{[string map [list $field_encapsulator$field_seperator$field_encapsulator "\} \{" $field_encapsulator {}] $response]\}" + + # Check that the response from Authorize.net is a legimate ADC + # response. When Authorize.net has problems the response is + # not a character delimited list but an HTML page. An ADC + # response has certainly 38 or more elements. Future + # versions might return more elements. + + if { [llength $response_list] < 38 } { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "PRIOR_AUTH_CAPTURE" $response 3 "" \ + "Authorize.net must be down, the response was not a character delimited list" "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Authorize.net must be down, the response was not a character delimited list" + set return(transaction_id) $transaction_id + return [array get return] + } else { + set response_code [lindex $response_list 0] + set response_reason_code [lindex $response_list 2] + set response_reason_text [lindex $response_list 3] + set response_auth_code [lindex $response_list 4] + set response_avs_code [lindex $response_list 5] + set response_transaction_id [lindex $response_list 6] + set response_md5_hash [lindex $response_list 37] + authorize_gateway.log_results $response_transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "PRIOR_AUTH_CAPTURE" \ + $response $response_code $response_reason_code $response_reason_text $response_auth_code $response_avs_code $amount + + # 3. Return result + + return [authorize_gateway.decode_response $transaction_id $response_transaction_id $response_code $response_reason_code \ + $response_reason_text $response_md5_hash $amount] + } + } +} + +ad_proc -private authorize_gateway.authcapture { + transaction_id + amount + card_type + card_number + card_exp_month + card_exp_year + card_name + billing_street + billing_city + billing_state + billing_zip + billing_country +} { + Connect to Authorize.net to authorize and shedule the transaction for automatic + settling. No further action is needed to complete the transastion. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + # 1. Send transaction off to gateway + + set test_request [authorize_gateway.decode_test_request] + set field_seperator [ad_parameter field_seperator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_seperator]] + set field_encapsulator [ad_parameter field_encapsulator -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] field_encapsulator]] + set referer_url [ad_parameter referer_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] referer_url]] + + # Add the Referer to the headers passed on to Authorize.net + + set header [ns_set new] + ns_set put $header Referer $referer_url + + # Compile the URL for the GET communication with Authorize.net + + # Basic secure URL and account info. + + set full_url "[ad_parameter authorize_url -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_url]]?x_Login=[ns_urlencode [ad_parameter authorize_login -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_login]]]&x_Password=[ns_urlencode [ad_parameter authorize_password -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_password]]]" + + # Add necessary ADC (Authorize.net Direct Connect) info such as the delimiting character. + + append full_url "&x_ADC_URL=False&x_ADC_Delim_Data=True&x_ADC_Delim_Character=[ns_urlencode $field_seperator]" + + # Set the test request flag to indicate trial communication or a real live transaction. + + append full_url "&x_Test_Request=[ns_urlencode $test_request]" + + # Set the transaction type to AUTH_CAPTURE and set the invoice + # number to the transaction id paramater. This is a bit confusing + # as the transaction id passed to this procedure should not be + # mistaken for the transaction id that Authorize.net will generate + # and return. The Authorize.net transaction id will be store in + # the response_transaction_id. + + append full_url "&x_Type=AUTH_CAPTURE&x_Amount=[ns_urlencode [format "%0.2f" $amount]]&x_Invoice_Num=$transaction_id&x_Description=[ns_urlencode [ad_parameter "description"]]" + + # Set the credit card information. + + append full_url "&x_Card_Num=[ns_urlencode $card_number]&x_Exp_Date=[ns_urlencode ${card_exp_month}/${card_exp_year}]&x_Last_Name=[ns_urlencode $card_name]" + + # Set the billing information. The information will be used by + # Authorize.net to run an AVS check. + + append full_url "&x_Address=[ns_urlencode $billing_street]&x_City=[ns_urlencode $billing_city]&x_Zip=[ns_urlencode $billing_zip]&x_State=[ns_urlencode $billing_state]&x_Country=[ns_urlencode $billing_country]" + + # Contact Authorize.net and receive the character delimited + # response. Timeout after 30 seconds, don't allow any redirects + # and pass a set of custom headers to Authorize.net. + + if {[catch {set response [ns_httpsget $full_url 30 0 $header]} error_message]} { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "AUTH_CAPTURE" $error_message 3 "" \ + $error_message "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Transaction $transaction_id failed, could not contact Authorize.net: $error_message" + set return(transaction_id) $transaction_id + return [array get return] + } else { + + # 2. Insert into log table + + # Decode the response from Authorize.net. Not all fields are + # of interest. See the Authorize.net documentation + # (https://secure.authorize.net/docs/response.pml) + # for a complete list of response codes. + + set response_list "\{[string map [list $field_encapsulator$field_seperator$field_encapsulator "\} \{" $field_encapsulator {}] $response]\}" + + # Check that the response from Authorize.net is a legimate ADC + # response. When Authorize.net has problems the response is + # not a character delimited list but an HTML page. An ADC + # response has certainly 38 or more elements. Future versions + # might return more elements. + + if { [llength $response_list] < 38 } { + authorize_gateway.log_results $transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "AUTH_CAPTURE" $response 3 "" \ + "Authorize.net must be down, the response was not a character delimited list" "" "" $amount + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "Authorize.net must be down, the response was not a character delimited list" + set return(transaction_id) $transaction_id + return [array get return] + } else { + set response_code [lindex $response_list 0] + set response_reason_code [lindex $response_list 2] + set response_reason_text [lindex $response_list 3] + set response_auth_code [lindex $response_list 4] + set response_avs_code [lindex $response_list 5] + set response_transaction_id [lindex $response_list 6] + set response_md5_hash [lindex $response_list 37] + authorize_gateway.log_results $response_transaction_id "[clock format [clock seconds] -format "%D %H:%M:%S"]" "AUTH_CAPTURE" \ + $response $response_code $response_reason_code $response_reason_text $response_auth_code $response_avs_code $amount + + # 3. Return result + + return [authorize_gateway.decode_response $transaction_id $response_transaction_id $response_code $response_reason_code $response_reason_text \ + $response_md5_hash $amount] + } + } +} + +ad_proc -private authorize_gateway.decode_response { + transaction_id + response_transaction_id + response_code + response_reason_code + response_reason_text + response_md5_hash + amount +} { + Decode the response from Authorize.net. Check authenticity, then map + Authorize.net response codes to standardized payment service + contract response codres. + + @author Bart Teeuwisse + @creation-date March 2002 +} { + + # Check if the response is authentic. The MD5 hash is a + # security feature that enables your script to identify that + # the results of a transaction are actually from + # Authorize.Net. This is done by creating a "secret" in your + # account. An MD5 hash is a specific way of encrypting + # information to make it unreadable unless the secret is + # known. Every time we return the results of a transaction, we + # also return the MD5 hash. It is created as with your secret, + # your Login ID, and two fields from the transaction. It is a + # concatenated string of those four items in the following + # order: + + # "MD5-Secret (assigned by merchant in the settings area)", + # "Login ID", "Trans ID", "Amount" + + # For an example, if your secret was "secret", your Login ID + # was "mylogin", the transaction ID was "987654321", and the + # amount was "1.00", the MD5 would be run on the following + # string: "secretmylogin9876543211.00" + + # When your script receives the results of the transaction you + # can create an MD5 hash on your side and be sure it matches + # ours. You will already know your secret and your login ID, + # and will receive the Transaction ID and amount in the + # results. + + # You can choose your MD5 Hash Secret by doing the following: + # -Log into your merchant menu at (https://secure.authorize.net/). + # -Click Settings. + # -Select Automated Direct Connect (ADC) Settings. + # -Click Go. + # -Enter the MD5 Hash Secret that you would like to use. + # -Click Submit to save the changes. + + # Don't forget to store the same MD5 Hash Secret in the + # md5_secret parameter of the Authorize.net Gateway in + # OpenACS. + + # The dqd_md5 functions is provided by Rob Mayoff's dqd_utils + # module for AOLServer. (http://dqd.com/~mayoff/aolserver/) + + set md5_hash [string tolower [dqd_md5 "[ad_parameter md5_secret -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] md5_secret]][ad_parameter authorize_login -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] authorize_login]]$response_transaction_id[format "%0.2f" $amount]"]] + if {$md5_hash == [string tolower $response_md5_hash]} { + + # The response is authentic. Now decode the response code + # and the reason code. + + switch -exact $response_code { + "1" { + set return(response_code) [nsv_get payment_gateway_return_codes success] + set return(reason) "Transaction $response_transaction_id has been approved." + set return(transaction_id) $response_transaction_id + return [array get return] + } + "2" { + set return(response_code) [nsv_get payment_gateway_return_codes failure] + set return(reason) "Transaction $response_transaction_id has been declined: $response_reason_text" + set return(transaction_id) $transaction_id + return [array get return] + } + "3" { + + # Some of the transactions that encountered an + # error while being processed can be retried in a + # little while. See the Authorize.net + # documentation + # (https://secure.authorize.net/docs/response.pml) + # for a complete list of response codes. + + switch -exact $response_reason_code { + "11" - + "19" - + "20" - + "21" - + "22" - + "23" - + "25" - + "26" { + set return(response_code) [nsv_get payment_gateway_return_codes retry] + set return(reason) "There has been an error processing transaction $response_transaction_id: $response_reason_text" + set return(transaction_id) $transaction_id + return [array get return] + } + default { + + # All other transactions failed indefinitely. + + set return(response_code) [nsv_get payment_gateway_return_codes failure] + set return(reason) "There has been an error processing transaction $response_transaction_id: $response_reason_text" + set return(transaction_id) $transaction_id + return [array get return] + } + } + } + default { + set return(response_code) [nsv_get payment_gateway_return_codes not_implemented] + set return(reason) "Authorize.net returned an unknown response_code: $response_code" + set return(transaction_id) $transaction_id + return [array get return] + } + } + } else { + set return(response_code) [nsv_get payment_gateway_return_codes failure] + set return(reason) "There has been an error processing transaction $response_transaction_id: the MD5 hash does not match" + set return(transaction_id) $transaction_id + return [array get return] + } +} + +ad_proc -private authorize_gateway.decode_test_request { +} { + Set test_request to True/False based on the test_request parameter of the + package. This prevents errors due to incorrect values of the test_request + parameter + + @author Bart Teeuwisse + @creation-date March 2002 +} { + + switch -exact [string tolower [ad_parameter test_request -default [ad_parameter -package_id [apm_package_id_from_key authorize-gateway] test_request]]] { + "0" - + "n" - + "no" - + "false" { + set test_request "False" + } + "1" - + "y" - + "yes" - + "true" { + set test_request "True" + } + default { + set test_request "False" + } + } + return $test_request +} + +ad_proc -private authorize_gateway.log_results { + transaction_id + txn_attempted_time + txn_attempted_type + response + response_code + response_reason_code + response_reason_text + auth_code + avs_code + amount +} { + Write the results of the current operation to the database. If it fails, + log it but don't let the user know about it. + + @author Bart Teeuwisse +} { + if [catch {db_dml do-insert " + insert into authorize_gateway_result_log + (transaction_id, txn_attempted_time, txn_attempted_type, response, response_code, response_reason_code, response_reason_text, response_transaction_id, + auth_code, avs_code, amount) + values + (:transaction_id, :txn_attempted_time, :txn_attempted_type, :response, :response_code, :response_reason_code, :response_reason_text, :response_transaction_id, + :auth_code, :avs_code, :amount)"} errmsg] { + ns_log Error "Wasn't able to do insert into authorize_gateway_result_log for transaction_id $transaction_id; error was $errmsg" + } +} Index: openacs-4/packages/authorize-gateway/tcl/authorize-gateway-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/tcl/authorize-gateway-procs.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/tcl/authorize-gateway-procs.xql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,45 @@ + + + + + + + select transaction_id, auth_code + from authorize_gateway_result_log + where txn_attempted_type='AUTH_ONLY' + and response_code='1' + and transaction_id=:transaction_id + + + + + + insert into authorize_gateway_result_log + (transaction_id, txn_attempted_type, txn_attempted_time, response, response_code, + response_reason_code, response_reason_text, auth_code, avs_code, amount) + values + (:transaction_id, :txn_attempted_type, :txn_attempted_time, :response, :response_code, + :response_reason_code, :response_reason_text, :auth_code, :avs_code, :amount) + + + + + + select version_name + from apm_package_versions + where enabled_p = 't' + and package_key = 'authorize-gateway' + + + + + + select instance_name + from apm_packages p, apm_package_versions v + where p.package_key = v.package_key + and v.enabled_p = 't' + and p.package_key = 'authorize-gateway' + + + + Index: openacs-4/packages/authorize-gateway/www/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/index.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/index.adp 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,20 @@ + + + + @title@ + +

@title@

+ + + + + + + +
@context_bar@ + + [ Administer ] + +
+
+

This package has no user pages.

Index: openacs-4/packages/authorize-gateway/www/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/index.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/index.tcl 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,38 @@ +ad_page_contract { + + A place holder for access to the admin pages. + + @author Bart Teeuwisse + @creation-date April 2002 + +} { +} -properties { + title:onevalue + context_bar:onevalue +} + +# Authenticate the user + +set user_id [ad_maybe_redirect_for_registration] + +# Check for admin privileges + +set package_id [ad_conn package_id] +set admin_p [ad_permission_p $package_id admin] + +# Get the name of the package + +if {[db_0or1row get_package_name " + select p.instance_name + from apm_packages p, apm_package_versions v + where p.package_id = :package_id + and p.package_key = v.package_key + and v.enabled_p = 't'"]} { + set title "$instance_name" +} else { + set title "Authorize.net Gateway" +} + +# Set the context bar. + +set context_bar [ad_context_bar] Index: openacs-4/packages/authorize-gateway/www/index.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/index.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/index.xql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,15 @@ + + + + + + + select p.instance_name + from apm_packages p, apm_package_versions v + where p.package_id = :package_id + and p.package_key = v.package_key + and v.enabled_p = 't' + + + + Index: openacs-4/packages/authorize-gateway/www/admin/index-postgresql.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/admin/index-postgresql.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/admin/index-postgresql.xql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,32 @@ + + + + postgresql7.1 + + + + txn_attempted_time + '1 days'::interval > now() + + + + + + txn_attempted_time + '7 days'::interval > now() + + + + + + txn_attempted_time + '1 months'::interval > now() + + + + + + select transaction_id, to_char(txn_attempted_time, 'MM-DD-YYYY HH24:MI:SS') as txn_time, txn_attempted_type, response, response_code, response_reason_code, response_reason_text, auth_code, avs_code, amount + from authorize_gateway_result_log + where '1'='1' [ad_dimensional_sql $dimensional] [ad_order_by_from_sort_spec $orderby $table_def] + + + + \ No newline at end of file Index: openacs-4/packages/authorize-gateway/www/admin/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/admin/index.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/admin/index.adp 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,16 @@ + +@title@ + +

@title@

+ + + + + + + +
@context_bar@[ help ]
+
+@dimensional_bar@ +

@result_table@

+ Index: openacs-4/packages/authorize-gateway/www/admin/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/admin/index.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/admin/index.tcl 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,80 @@ +ad_page_contract { + + Lists the log of the results + + @author Bart Teeuwisse + @creation-date April 2002 +} { + {orderby "txn_time*"} +} -properties { + title:onevalue + context_bar:onevalue + dimensional_bar:onevalue +} + +# Authenticate the user + +set user_id [ad_maybe_redirect_for_registration] + +# Check for admin privileges + +set package_id [ad_conn package_id] +set admin_p [ad_permission_p $package_id admin] + +# Get the package name and set the title. + +if {[db_0or1row get_package_name " + select p.instance_name + from apm_packages p, apm_package_versions v + where p.package_id = :package_id + and p.package_key = v.package_key + and v.enabled_p = 't'"]} { + set title "$instance_name Administration" +} else { + set title "Administration" +} + +# Set the context bar. + +set context_bar [ad_context_bar] + +# Dimensional slider definition for narrowing the selection. + +set dimensional { + {response_code "Result" approved { + {approved "approved" {where "[db_map result_approved]"} } + {declined "declined" {where "[db_map result_declined]"} } + {error "error" {where "[db_map result_error]"} } + {any "all" {} } + } } + {transaction "Time of transaction" 1d { + {1d "last 24 hours" {where "[db_map transaction_last_24hours]"}} + {1w "last week" {where "[db_map transaction_last_week]"}} + {1m "last month" {where "[db_map transaction_last_month]"}} + {any "all" {} } + } } +} +set dimensional_bar [ad_dimensional $dimensional] + +# Definition for ad_table. + +set table_def { + {transaction_id "ID" {} {}} + {txn_time "Date" {txn_attempted_time desc} {}} + {txn_attempted_type "Type" {} {}} + {response_code "Result" {} {}} + {response_reason_code "Reason" {} {}} + {response_reason_text "Explanation" no_sort {}} + {auth_code "Authorization" {} {}} + {avs_code "AVS" {} {}} + {response "Verbatim response" no_sort {}} +} + +# Create the table to display the results from Authorize.net + +set result_table [ad_table result_select " + select transaction_id, to_char(txn_attempted_time, 'MM-DD-YYYY HH12:MI:SS AM') as txn_time, txn_attempted_type, response, response_code, response_reason_code, + response_reason_text, auth_code, avs_code, amount + from authorize_gateway_result_log + where '1'='1' [ad_dimensional_sql $dimensional] + [ad_order_by_from_sort_spec $orderby $table_def]" $table_def] Index: openacs-4/packages/authorize-gateway/www/admin/index.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/admin/index.xql,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/admin/index.xql 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,32 @@ + + + + + + select p.instance_name + from apm_packages p, apm_package_versions v + where p.package_id = :package_id + and p.package_key = v.package_key + and v.enabled_p = 't' + + + + + + response_code='1' + + + + + + response_code='2' + + + + + + response_code='3' + + + + Index: openacs-4/packages/authorize-gateway/www/doc/index.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/doc/index.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/doc/index.adp 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,243 @@ + + + + @title@ + @signatory@ + + +

@title@

+ + + + + + + +
@context_bar@ + + [ Administer ] + +
+
+ +

Why

+ +

The @package_name@ implements the Payment Service + Contract for the Authorize.net on-line merchant + services.

+ +

Background

+ +

Since the development of the ecommerce package VeriSign bought the + CyberCash credit card acceptance service that the ecommerce + package was build upon. VeriSign merged the CyberCash API with + their own product PayflowPro which left the ecommerce package + without a functioning credit card service.

+ +

Janine Sisk of furfly.net and Bart Teeuwisse + teamed up to design a general purpose payment service contract + and to create the first implementations of the contract. Janine + developed the interface to PayflowPro the successor of CyberCash + while Bart created the gateway to Authorize.net.

+ +

Berklee College Of Music + sponsored the creation of the @package_name@ and the integration + with the ecommerce package.

+ +

Usage

+ +

Note: This release has been developed on PostgreSQL + only. Please report any problems you might find in the OpenACS SDM. The SDM can also + be used to contribute patches to the @package_name@ package (for + example to add Oracle support).

+ +

The @package_name@ requires nsopenssl + and dqd_utils to + be installed. Nsopenssl provides the ns_httpsget and ns_httpspost + instructions to connect to the secure Authorize.net Direct Connect + server. Dqd_utils provides the dqd_md5 instruction to validate the + response from the Authorize.net Direct Connect server. Please + follow the installation instructions included with these + packages.

+ +

The @package_name@ is the intermediary between OpenACS packages + and the Authorize.net credit card acceptance services. This + gateway accepts calls to the Payment Service Contract operations, + forwards the information to Authorize.net and decodes the response + before returning the outcome back to the calling package while + keeping a log of all communication with Authorize.net. The log is + accessible from the @package_name@ administration.

+ +

The @package_name@ needs to be configured before it can connect + to Authorize.net and access your account with + Authorize.net. Configuration is via @package_name@ + parameters. The package + has 9 parameters:

+ +
    +
  1. + +

    CreditCardsAccepted

    + +

    A list of credit cards accepted by your Authorize.net + account. Calling applications can use this list of overwrite + it with their own list so that applications can choose to + accept only a subset of the cards your Authorize.net account + can handle.

    + +
  2. +
  3. + +

    description

    + +

    The description of the transaction as it will appear on the + customer's statement. E.g. 'ACME Widgets'

    + +
  4. +
  5. + +

    test_request

    + +

    Switch the communication with Authorize.net over to Test + mode. Useful to test the communication with Authorize.net from + the calling package. The default value is 'False'.

    + +

    Note: Transactions authorized in test mode do + not return a valid transaction ID and + will fail they are being post-authorized.

    + +
  6. +
  7. + +

    authorize_url

    + +

    The location (URL) of the Authorize.net Gateway. Unless you + received a different location from Authorize.net there is no + need to change the default value.

    + +
  8. +
  9. + +

    referer_url

    + +

    The location (URL) of your web site where the communication + with Authorize.net originates from. This URL be listed as a + valid ADC URL in the list of accepted referers in the ADC + settings. Do not leave this secret blank, it + ensures the requests received by Authorize.net are comming + from the @package_name@ and not some spoof.

    + +
  10. +
  11. + +

    authorize_login

    + +

    Your login name to Authorize.net. This is the same login ID + that you use to login to the Authorize.net virtual terminal.

    + +
  12. +
  13. + +

    authorize_password

    + +

    The password to your Authorize.net account. This is the same login ID + that you use to login to the Authorize.net virtual terminal.

    + +

    Advice: Keep your login name and the login password + secret as they give access all credit card transactions + including all credit card numbers of the cards used in the + transactions. Make sure to secure the access to the OpenACS + admin pages with SSL.

    + +
  14. +
  15. + +

    md5_secret

    + +

    The MD5 Hash Secret from the Automated Direct Connect + (ADC) settings in Authorize.net. This secret should have the + same value your secret in the ADC settings. Do + not leave this secret blank, it ensures that + the @package_name@ is really talking to Authorize.net and not + some spoof.

    + +
  16. +
  17. + +

    field_encapsulator

    + +

    The field encapsulation character in the Automated Direct + Connect (ADC) settings of Authorize.net. You can opt to use a + field encapsulation character to wrap around the elements in the + response from Authorize.net. It reduces the risk that unusual + characters in the data send to Authorize.net and echoed back + trip the decoding of the response. With only a field separator + it is possible that the decoding is disrupted by a name or + address field containing the same character as the field + separator. If you choose to use a field encapsulator make sure + that the value is same as the value in the ADC settings.

    + +
  18. +
  19. + +

    field_seperator

    + +

    The field seperator in Automated Direct Connect (ADC) + Settings of Authorize.net. This is the character that delimits + the elements in the response from Authorize.net. It is advisable + to also use a field encapsulator. Make sure that the value is + same as the value in the ADC settings.

    + +
  20. +
+ +

API Reference

+ +

The Payment Service Contract explains the API to other + packages in detail.

+ +

Visit the Authorize.net + developer documentation for in-depth coverage of the + Authorize.net API that this package interfaces to. Be sure to check + out the additional security measures you can take.

+ +

Credits

+ +

The @package_name@ was designed and written by Bart Teeuwisse + for Berklee College Of + Music while working as a subcontractor for furfly.net.

+ +

The @package_name@ is free software; you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version.

+ +

The @package_name@ is distributed in the hope that it will be + useful, but WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU General Public License for more details.

+ +

A copy of the GNU General Public License is + included. If not write to the Free Software Foundation, Inc., 59 + Temple Place, Suite 330, Boston, MA 02111-1307 USA Index: openacs-4/packages/authorize-gateway/www/doc/index.css =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/doc/Attic/index.css,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/doc/index.css 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,5 @@ +p.note { + font-style: italic; + padding: 10; + background-color: lightgrey; +} Index: openacs-4/packages/authorize-gateway/www/doc/index.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/doc/index.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/doc/index.tcl 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,44 @@ +ad_page_contract { + + Index to documentation of the Authorize.net Gateway, an + implementation of the Payment Service Contract. + + @author Bart Teeuwisse + @creation-date May 2002 + +} { +} -properties { + title:onevalue + context_bar:onevalue +} + +# Authenticate the user + +set user_id [ad_maybe_redirect_for_registration] + +set package_name "Authorize.net Gateway" +set title "$package_name Documentation" +set package_url [apm_package_url_from_key "authorize-gateway"] +set package_id [apm_package_id_from_key "authorize-gateway"] + +# Check if the package has been mounted. + +set authorize_gateway_mounted [expr ![empty_string_p $package_url]] + +# Check for admin privileges + +set admin_p [ad_permission_p $package_id admin] + +# Check if the ecommerce and the shipping service contract packages +# are installed on the system. + +set ecommerce_installed [apm_package_installed_p ecommerce] +set payment_gateway_installed [apm_package_installed_p "payment-gateway"] + +# Set the context bar. + +set context_bar [ad_context_bar $package_name] + +# Set signatory for at the bottom of the page + +set signatory "bart.teeuwisse@7-sisters.com" Index: openacs-4/packages/authorize-gateway/www/doc/license.adp =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/doc/license.adp,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/doc/license.adp 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,328 @@ + + + + @title@ + @signatory@ + + +

@title@

+ + + + + + +
@context_bar@
+
+ +

GNU General Public License

+ +

Version 2, June 1991

+ +
+    Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+    Everyone is permitted to copy and distribute verbatim copies
+    of this license document, but changing it is not allowed.
+  
+ +

Preamble

+ +

The licenses for most software are designed to take away your + freedom to share and change it. By contrast, the GNU General + Public License is intended to guarantee your freedom to share and + change free software--to make sure the software is free for all + its users. This General Public License applies to most of the + Free Software Foundation's software and to any other program whose + authors commit to using it. (Some other Free Software Foundation + software is covered by the GNU Library General Public License + instead.) You can apply it to your programs, too.

+ +

When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that + you have the freedom to distribute copies of free software (and + charge for this service if you wish), that you receive source code + or can get it if you want it, that you can change the software or + use pieces of it in new free programs; and that you know you can + do these things.

+ +

To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the + rights. These restrictions translate to certain responsibilities + for you if you distribute copies of the software, or if you modify + it.

+ +

For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights + that you have. You must make sure that they, too, receive or can + get the source code. And you must show them these terms so they + know their rights.

+ +

We protect your rights with two steps: (1) copyright the + software, and (2) offer you this license which gives you legal + permission to copy, distribute and/or modify the software.

+ +

Also, for each author's protection and ours, we want to make + certain that everyone understands that there is no warranty for + this free software. If the software is modified by someone else + and passed on, we want its recipients to know that what they have + is not the original, so that any problems introduced by others + will not reflect on the original authors' reputations.

+ +

Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a + free program will individually obtain patent licenses, in effect + making the program proprietary. To prevent this, we have made it + clear that any patent must be licensed for everyone's free use or + not licensed at all.

+ +

The precise terms and conditions for copying, distribution and + modification follow.

+ +

Terms and conditions for copying, distribution and modification

+ +

0. This License applies to any program or other + work which contains a notice placed by the copyright holder saying + it may be distributed under the terms of this General Public + License. The "Program", below, refers to any such program or + work, and a "work based on the Program" means either the Program + or any derivative work under copyright law: that is to say, a work + containing the Program or a portion of it, either verbatim or with + modifications and/or translated into another language. + (Hereinafter, translation is included without limitation in the + term "modification".) Each licensee is addressed as "you".

+ +

Activities other than copying, distribution and modification are + not covered by this License; they are outside its scope. The act + of running the Program is not restricted, and the output from the + Program is covered only if its contents constitute a work based on + the Program (independent of having been made by running the + Program). Whether that is true depends on what the Program does.

+ +

1. You may copy and distribute verbatim copies + of the Program's source code as you receive it, in any medium, + provided that you conspicuously and appropriately publish on each + copy an appropriate copyright notice and disclaimer of warranty; + keep intact all the notices that refer to this License and to the + absence of any warranty; and give any other recipients of the + Program a copy of this License along with the Program.

+ + +

You may charge a fee for the physical act of transferring a copy, + and you may at your option offer warranty protection in exchange + for a fee.

+ +

2. You may modify your copy or copies of the + Program or any portion of it, thus forming a work based on the + Program, and copy and distribute such modifications or work under + the terms of Section 1 above, provided that you also meet all of + these conditions:

+ +
    + +
  • a) You must cause the modified files to carry + prominent notices stating that you changed the files and the + date of any change.

  • + +
  • b) You must cause any work that you + distribute or publish, that in whole or in part contains or is + derived from the Program or any part thereof, to be licensed as + a whole at no charge to all third parties under the terms of + this License.

  • + +
  • c) If the modified program normally reads + commands interactively when run, you must cause it, when started + running for such interactive use in the most ordinary way, to + print or display an announcement including an appropriate + copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may + redistribute the program under these conditions, and telling the + user how to view a copy of this License. (Exception: if the + Program itself is interactive but does not normally print such + an announcement, your work based on the Program is not required + to print an announcement.)

  • +
+ +

These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the + Program, and can be reasonably considered independent and separate + works in themselves, then this License, and its terms, do not + apply to those sections when you distribute them as separate + works. But when you distribute the same sections as part of a + whole which is a work based on the Program, the distribution of + the whole must be on the terms of this License, whose permissions + for other licensees extend to the entire whole, and thus to each + and every part regardless of who wrote it.

+ +

Thus, it is not the intent of this section to claim rights or + contest your rights to work written entirely by you; rather, the + intent is to exercise the right to control the distribution of + derivative or collective works based on the Program.

+ +

In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on + a volume of a storage or distribution medium does not bring the + other work under the scope of this License.

+ +

3. You may copy and distribute the Program (or + a work based on it, under Section 2) in object code or executable + form under the terms of Sections 1 and 2 above provided that you + also do one of the following:

+ +
    + +
  • a) Accompany it with the complete + corresponding machine-readable source code, which must be + distributed under the terms of Sections 1 and 2 above on a + medium customarily used for software interchange; or,

  • + +
  • b) Accompany it with a written offer, + valid for at least three years, to give any third party, for a + charge no more than your cost of physically performing source + distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Sections 1 and 2 above on a medium customarily used for software + interchange; or,

  • + +
  • c) Accompany it with the information you + received as to the offer to distribute corresponding source + code. (This alternative is allowed only for noncommercial + distribution and only if you received the program in object code + or executable form with such an offer, in accord with Subsection + b above.)

  • +
+ +

The source code for a work means the preferred form of the work + for making modifications to it. For an executable work, complete + source code means all the source code for all modules it contains, + plus any associated interface definition files, plus the scripts + used to control compilation and installation of the executable. + However, as a special exception, the source code distributed need + not include anything that is normally distributed (in either + source or binary form) with the major components (compiler, + kernel, and so on) of the operating system on which the executable + runs, unless that component itself accompanies the executable.

+ +

If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent + access to copy the source code from the same place counts as + distribution of the source code, even though third parties are not + compelled to copy the source along with the object code.

+ +

4. You may not copy, modify, sublicense, or + distribute the Program except as expressly provided under this + License. Any attempt otherwise to copy, modify, sublicense or + distribute the Program is void, and will automatically terminate + your rights under this License. However, parties who have + received copies, or rights, from you under this License will not + have their licenses terminated so long as such parties remain in + full compliance.

+ +

5. You are not required to accept this + License, since you have not signed it. However, nothing else + grants you permission to modify or distribute the Program or its + derivative works. These actions are prohibited by law if you do + not accept this License. Therefore, by modifying or distributing + the Program (or any work based on the Program), you indicate your + acceptance of this License to do so, and all its terms and + conditions for copying, distributing or modifying the Program or + works based on it.

+ +

6. Each time you redistribute the Program (or any + work based on the Program), the recipient automatically receives a + license from the original licensor to copy, distribute or modify + the Program subject to these terms and conditions. You may not + impose any further restrictions on the recipients' exercise of the + rights granted herein. You are not responsible for enforcing + compliance by third parties to this License.

+ +

7. If, as a consequence of a court judgment or + allegation of patent infringement or for any other reason (not + limited to patent issues), conditions are imposed on you (whether + by court order, agreement or otherwise) that contradict the + conditions of this License, they do not excuse you from the + conditions of this License. If you cannot distribute so as to + satisfy simultaneously your obligations under this License and any + other pertinent obligations, then as a consequence you may not + distribute the Program at all. For example, if a patent license + would not permit royalty-free redistribution of the Program by all + those who receive copies directly or indirectly through you, then + the only way you could satisfy both it and this License would be + to refrain entirely from distribution of the Program.

+ +

If any portion of this section is held invalid or unenforceable + under any particular circumstance, the balance of the section is + intended to apply and the section as a whole is intended to apply + in other circumstances.

+ +

It is not the purpose of this section to induce you to infringe + any patents or other property right claims or to contest validity + of any such claims; this section has the sole purpose of + protecting the integrity of the free software distribution system, + which is implemented by public license practices. Many people + have made generous contributions to the wide range of software + distributed through that system in reliance on consistent + application of that system; it is up to the author/donor to decide + if he or she is willing to distribute software through any other + system and a licensee cannot impose that choice.

+ +

This section is intended to make thoroughly clear what is + believed to be a consequence of the rest of this License.

+ +

8. If the distribution and/or use of the Program + is restricted in certain countries either by patents or by + copyrighted interfaces, the original copyright holder who places + the Program under this License may add an explicit geographical + distribution limitation excluding those countries, so that + distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation + as if written in the body of this License.

+ +

9. The Free Software Foundation may publish + revised and/or new versions of the General Public License from + time to time. Such new versions will be similar in spirit to the + present version, but may differ in detail to address new problems + or concerns.

+ +

Each version is given a distinguishing version number. If the + Program specifies a version number of this License which applies + to it and "any later version", you have the option of following + the terms and conditions either of that version or of any later + version published by the Free Software Foundation. If the Program + does not specify a version number of this License, you may choose + any version ever published by the Free Software Foundation.

+ +

10. If you wish to incorporate parts of the + Program into other free programs whose distribution conditions are + different, write to the author to ask for permission. For + software which is copyrighted by the Free Software Foundation, + write to the Free Software Foundation; we sometimes make + exceptions for this. Our decision will be guided by the two goals + of preserving the free status of all derivatives of our free + software and of promoting the sharing and reuse of software + generally.

+ +

NO WARRANTY

+ +

11. BECAUSE THE PROGRAM IS LICENSED FREE OF + CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT + PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN + WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE + PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR + IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE + RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. + SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION.

+ +

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW + OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER + PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED + ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, + SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE + USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO + LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED + BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE + WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS + BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

Index: openacs-4/packages/authorize-gateway/www/doc/license.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/authorize-gateway/www/doc/license.tcl,v diff -u --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ openacs-4/packages/authorize-gateway/www/doc/license.tcl 21 May 2002 18:36:25 -0000 1.1 @@ -0,0 +1,28 @@ +ad_page_contract { + + License information of the Authorize.net Gateway, an + implementation of the Payment Service Contract. + + @author Bart Teeuwisse + @creation-date May 2002 + +} { +} -properties { + title:onevalue + context_bar:onevalue +} + +# Authenticate the user + +set user_id [ad_maybe_redirect_for_registration] + +set package_name "Authorize.net Gateway" +set title "$package_name License" + +# Set the context bar. + +set context_bar [ad_context_bar [list . $package_name] License] + +# Set signatory for at the bottom of the page + +set signatory "bart.teeuwisse@7-sisters.com"