6.x-2.x branch
Use Google Checkout to collect payment and process orders.
- <?php
-
- /**
- * @file
- * Use Google Checkout to collect payment and process orders.
- */
-
- /******************************************************************************
- * Drupal hooks *
- ******************************************************************************/
-
- /**
- * Implements hook_help().
- */
- function uc_google_checkout_help($page, $args) {
- $output = '';
- switch ($page) {
- case 'admin/store/settings/google_checkout':
- if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
- $checkout_url = 'http://checkout.google.com';
- }
- else {
- $checkout_url = 'http://sandbox.google.com/checkout';
- }
- $output .= t('In the <a href="!checkout_url/sell">Google Checkout Merchant Center</a>, enter %url as the callback URL for this site. Also be sure that "Callback contents" is set to "Notification Serial Number" and that the API Version is 2.5.', array('!checkout_url' => $checkout_url, '%url' => url('google_checkout', array('absolute' => TRUE))));
- break;
- }
- return $output;
- }
-
- /**
- * Implements hook_menu().
- */
- function uc_google_checkout_menu() {
- $items = array();
-
- $items['admin/store/settings/google_checkout'] = array(
- 'title' => 'Google Checkout settings',
- 'description' => 'Set merchant ID and key for Google Checkout.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('uc_google_checkout_settings'),
- 'access arguments' => array('administer store'),
- 'type' => MENU_NORMAL_ITEM,
- 'file' => 'uc_google_checkout.admin.inc',
- );
- $items['admin/store/settings/google_checkout/account'] = array(
- 'title' => 'Account',
- 'type' => MENU_DEFAULT_LOCAL_TASK,
- );
- $items['admin/store/settings/google_checkout/shipping'] = array(
- 'title' => 'Shipping',
- 'description' => 'Calculate shipping charges for orders through Google Checkout.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('uc_google_checkout_shipping_settings'),
- 'access arguments' => array('administer store'),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'uc_google_checkout.admin.inc',
- );
- $items['admin/store/settings/google_checkout/taxes'] = array(
- 'title' => 'Taxes',
- 'description' => 'Calculate taxes for orders through Google Checkout.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('uc_google_checkout_taxes_settings'),
- 'access arguments' => array('administer store'),
- 'type' => MENU_LOCAL_TASK,
- 'file' => 'uc_google_checkout.admin.inc',
- );
- $items['google_checkout'] = array(
- 'page callback' => 'uc_google_checkout_callback',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- 'file' => 'uc_google_checkout.pages.inc',
- );
- $items['google_checkout/calculations'] = array(
- 'page callback' => 'uc_google_checkout_merchant_calculation',
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- 'file' => 'uc_google_checkout.pages.inc',
- );
- $items['admin/store/orders/%uc_order/google_checkout'] = array(
- 'title callback' => 'uc_google_checkout_terminal_title',
- 'title arguments' => array(3),
- 'description' => 'Process a credit card payment or refund through Google Checkout.',
- 'page callback' => 'uc_google_checkout_terminal',
- 'page arguments' => array(3),
- 'access arguments' => array('manual payments'),
- 'type' => MENU_CALLBACK,
- 'file' => 'uc_google_checkout.admin.inc',
- );
-
- return $items;
- }
-
- /**
- * Menu title callback function.
- */
- function uc_google_checkout_terminal_title($order) {
- return t('Google Checkout terminal: Order @order_id', array('@order_id' => $order->order_id));
- }
-
- /**
- * Implements hook_init().
- */
- function uc_google_checkout_init() {
- // When an order comes in from Google Checkout, we need to unset some
- // $_SESSION data. Since this isn't done under the customer's user, we
- // do it when they next load a page.
- global $user;
- $users = variable_get('uc_google_checkout_order_users', array());
- if (isset($users[$user->uid])) {
- unset($_SESSION['cart_order'], $_SESSION['do_complete'], $users[$user->uid]);
- variable_set('uc_google_checkout_order_users', $users);
- }
-
- global $conf;
- $conf['i18n_variables'][] = 'uc_google_checkout_order_cancel_reason';
-
- $id = variable_get('googleanalytics_account', '');
- if (module_exists('googleanalytics') && !empty($id) && _googleanalytics_visibility_pages() && _googleanalytics_visibility_user($user)) {
- $scope = variable_get('googleanalytics_js_scope', 'footer');
- drupal_add_js('document.write(unescape("%3Cscript src=\"//checkout.google.com/files/digital/ga_post.js\" type=\"text/javascript\"%3E%3C/script%3E"));', 'inline', $scope);
- }
- }
-
- /**
- * Implements hook_theme().
- */
- function uc_google_checkout_theme() {
- return array(
- 'uc_google_checkout_shipping_settings' => array(
- 'arguments' => array('form' => NULL),
- 'file' => 'uc_google_checkout.admin.inc',
- ),
- 'uc_google_checkout_taxes_settings' => array(
- 'arguments' => array('form' => NULL),
- 'file' => 'uc_google_checkout.admin.inc',
- ),
- );
- }
-
- /**
- * Implements hook_form_alter().
- */
- function uc_google_checkout_form_alter(&$form, $form_state, $form_id) {
- if (uc_product_is_product_form($form)) {
- $node = $form['#node'];
- if (is_object($node) && $form_id == $node->type .'_node_form' && uc_product_is_product($node->type)) {
- $policy_url = 'https://checkout.google.com/support/sell/bin/answer.py?answer=75724';
- $form['google_checkout'] = array(
- '#type' => 'fieldset',
- '#title' => t('Google Checkout settings'),
- '#collapsible' => TRUE,
- '#collapsed' => TRUE,
- );
- $form['google_checkout']['gc_salable'] = array(
- '#type' => 'checkbox',
- '#title' => t('Conforms to Google Checkout content policies.'),
- '#default_value' => isset($node->gc_salable) ? $node->gc_salable : TRUE,
- '#description' => t('To be a Google Checkout approved merchant, your items must conform to the Google Checkout content policies found <a href="!url">here</a>.', array('!url' => $policy_url)),
- );
- }
- }
- elseif ($form_id == 'uc_payment_methods_form') {
- // Make sure no one enables this for Ubercart checkout.
- $form['pmtable']['google_checkout']['uc_payment_method_google_checkout_checkout']['#disabled'] = TRUE;
- $form['pmtable']['google_checkout']['uc_payment_method_google_checkout_checkout']['#value'] = FALSE;
- }
- elseif ($form_id == 'uc_payment_by_order_form') {
- // Don't use Google Checkout for manual payments either.
- unset($form['payments']['new']['method']['#options']['google_checkout']);
- }
- elseif ($form_id == 'uc_order_view_update_form') {
- $form['#submit'][] = 'uc_google_checkout_notify_update';
- }
- elseif ($form_id == 'uc_store_format_settings_form') {
- $form['currency']['uc_currency_code']['#description'] .= ' '. t('Google Checkout only accepts the following currencies: @list', array('@list' => implode(', ', _uc_google_checkout_currency_codes())));
- }
- }
-
- /**
- * Implements hook_nodeapi().
- */
- function uc_google_checkout_nodeapi(&$node, $op) {
- if (uc_product_is_product($node->type)) {
- switch ($op) {
- case 'insert':
- case 'update':
- if (isset($node->gc_salable)) {
- if (!$node->revision) {
- db_query("DELETE FROM {uc_gc_products} WHERE vid = %d", $node->vid);
- }
- db_query("INSERT INTO {uc_gc_products} (vid, nid, gc_salable) VALUES (%d, %d, %d)",
- $node->vid, $node->nid, $node->gc_salable);
- }
- break;
- case 'load':
- $salable = db_result(db_query("SELECT gc_salable FROM {uc_gc_products} WHERE vid = %d", $node->vid));
- if ($salable === FALSE) {
- $salable = TRUE;
- }
- return array('gc_salable' => $salable);
- break;
- case 'delete':
- db_query("DELETE FROM {uc_gc_products} WHERE nid = %d", $node->nid);
- break;
- case 'delete revision':
- db_query("DELETE FROM {uc_gc_products} WHERE vid = %d", $node->vid);
- break;
- }
- }
- }
-
- /******************************************************************************
- * Hook Functions (Ubercart) *
- ******************************************************************************/
-
- /**
- * Implements hook_cart_pane().
- */
- function uc_google_checkout_cart_pane() {
- $panes[] = array(
- 'id' => 'uc_google_checkout',
- 'title' => t('Google Checkout'),
- 'enabled' => TRUE,
- 'weight' => 1,
- 'body' => '<div align="'. variable_get('uc_google_checkout_button_align', 'right') .'">'. drupal_get_form('uc_google_checkout_cart_form') .'</div>',
- );
- return $panes;
- }
-
-
- /**
- * Implements hook_order_pane().
- */
- function uc_google_checkout_order_pane() {
- $panes[] = array(
- 'id' => 'email_allowed',
- 'callback' => 'uc_google_checkout_pane_email_allowed',
- 'title' => t('Marketing preferences'),
- 'desc' => t("Display the customer's preferences about mass-marketing."),
- 'class' => 'pos-left',
- 'weight' => 4,
- 'show' => array('view', 'customer'),
- );
-
- return $panes;
- }
-
- /**
- * Implements hook_line_item().
- */
- function uc_google_checkout_line_item() {
- $items[] = array(
- 'id' => 'gc_coupon',
- 'title' => t('Google Checkout Coupon'),
- 'stored' => TRUE,
- 'calculated' => TRUE,
- 'weight' => 2,
- );
- $items[] = array(
- 'id' => 'gc_gift_certificate',
- 'title' => t('Google Checkout Gift Certificate'),
- 'stored' => TRUE,
- 'calculated' => TRUE,
- 'weight' => 2,
- );
-
- return $items;
- }
-
- /**
- * Implements hook_order().
- */
- function uc_google_checkout_order($op, &$order, $arg2) {
- switch ($op) {
- case 'load':
- $result = db_query("SELECT * FROM {uc_gc_orders} WHERE order_id = %d", $order->order_id);
- if ($gc = db_fetch_object($result)) {
- $order->google_order_number = $gc->gc_order_number;
- $order->financial_state = $gc->financial_state;
- $order->fulfillment_state = $gc->fulfillment_state;
- $order->gc_total = $gc->gc_total;
- }
- break;
- case 'can_update':
- if (!isset($order->google_order_number) || isset($_SESSION['google_updates']) && $_SESSION['google_updates']) {
- return TRUE;
- }
- switch ($arg2) {
- case 'canceled':
- if (uc_google_checkout_cancel_order($order)) {
- drupal_set_message(t('Cancel order request sent to Google Checkout. The order will be updated momentarily.'));
- }
- else {
- drupal_set_message(t('Order is not canceled in Google Checkout.'));
- }
- return FALSE;
- }
- break;
- }
- }
-
- /**
- * Implements hook_payment_method().
- */
- function uc_google_checkout_payment_method() {
- $methods[] = array(
- 'id' => 'google_checkout',
- 'name' => t('Google Checkout'),
- 'title' => t('Google Checkout'),
- 'desc' => t('Express payment with Google Checkout.'),
- 'callback' => 'uc_payment_method_google_checkout',
- 'weight' => 1,
- 'checkout' => FALSE,
- 'backend' => FALSE,
- );
- return $methods;
- }
-
- /**
- * Implements hook_payment_gateway().
- */
- function uc_google_checkout_payment_gateway() {
- $gateways[] = array(
- 'id' => 'google_checkout',
- 'title' => t('Google Checkout'),
- 'description' => t('Express payment with Google Checkout.'),
- 'google_checkout' => 'uc_google_checkout_charge',
- );
- return $gateways;
- }
-
- /**
- * Implements hook_shipment().
- */
- function uc_google_checkout_shipment($op, $shipment) {
- switch ($op) {
- case 'save':
- $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
- if ($google_order_number && $shipment->is_new) {
- $xml_data = '';
- foreach ($shipment->packages as $package) {
- if ($package->tracking_number) {
- $tracking_number = $package->tracking_number;
- }
- elseif ($shipment->tracking_number) {
- $tracking_number = $shipment->tracking_number;
- }
- if ($tracking_number) {
- foreach ($package->products as $product) {
- $xml_data .= '<item-shipping-information>';
- $xml_data .= '<item-id>';
- $xml_data .= '<merchant-item-id>'. check_plain($product->nid .'|'. $product->model) .'</merchant-item-id>';
- $xml_data .= '</item-id>';
- $xml_data .= '<tracking-data-list>';
- $xml_data .= '<tracking-data>';
- $xml_data .= '<carrier>'. check_plain($shipment->carrier) .'</carrier>';
- $xml_data .= '<tracking-number>'. check_plain($tracking_number) .'</tracking-number>';
- $xml_data .= '</tracking-data>';
- $xml_data .= '</tracking-data-list>';
- $xml_data .= '</item-shipping-information>';
- }
- }
- }
- if ($xml_data) {
- $request = '<?xml version="1.0" encoding="UTF-8"?>';
- $request .= "\n";
- $request .= '<ship-items xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
- $request .= '<item-shipping-information-list>';
- $request .= $xml_data;
- $request .= '</item-shipping-information-list>';
- $request .= '<send-email>true</send-email>';
- $request .= '</ship-items>';
- $response = uc_google_checkout_send_request('request', $request);
- }
- }
- break;
- case 'delete':
- $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
- if ($google_order_number) {
- foreach ($shipment->packages as $package) {
- foreach ($package->products as $product) {
- $reset_ids[] = check_plain($product->nid .'|'. $product->model);
- }
- }
- $request = '<?xml version="1.0" encoding="UTF-8"?>';
- $request .= "\n";
- $request .= '<reset-items-shipping-information xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
- $request .= '<item-ids>';
- foreach (array_unique($reset_ids) as $item_id) {
- $request .= '<item-id>';
- $request .= '<merchant-item-id>'. $item_id .'</merchant-item-id>';
- $request .= '</item-id>';
- }
- $request .= '</item-ids>';
- $request .= '<send-email>false</send-email>';
- $request .= '</reset-items-shipping-information>';
-
- $response = uc_google_checkout_send_request('request', $request);
- }
- break;
- }
- }
-
- /******************************************************************************
- * Callback Functions, Forms, and Tables *
- ******************************************************************************/
-
- /**
- * Form builder for uc_google_checkout_cart_form().
- *
- * @see uc_google_checkout_cart_form_submit()
- * @ingroup forms
- */
- function uc_google_checkout_cart_form() {
- if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
- $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
- $checkout_url = 'https://checkout.google.com';
- }
- else {
- $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
- $checkout_url = 'https://sandbox.google.com/checkout';
- }
- if (!$merchant_id) {
- watchdog('google', 'Google Checkout is enabled, but no Merchant ID found.', array(), WATCHDOG_ERROR, 'admin/store/settings/google_checkout');
- return;
- }
-
- // Hack to allow the image button to submit.
- if (isset($_POST['submit_x'])) {
- $form['submit'] = array(
- '#type' => 'submit',
- '#value' => 'submit',
- );
- }
-
- global $user;
- $id = variable_get('googleanalytics_account', '');
- if (module_exists('googleanalytics') && !empty($id) && _googleanalytics_visibility_pages() && _googleanalytics_visibility_user($user)) {
- $form['#attributes'] = array('onsubmit' => 'setUrchinInputCode(pageTracker);');
- }
-
- $disable = FALSE;
- foreach (uc_cart_get_contents() as $item) {
- $product = node_load($item->nid);
- if (!$product->gc_salable) {
- $disable = TRUE;
- break;
- }
- }
-
- switch (variable_get('uc_google_checkout_button_size', 'large')) {
- case 'large':
- $width = 180;
- $height = 46;
- break;
- case 'medium':
- $width = 168;
- $height = 44;
- break;
- case 'small':
- $width = 160;
- $height = 43;
- break;
- }
-
- $form['submit_image'] = array(
- '#value' => ($disable ? '<img ' : '<input name="submit" type="image" ') .'alt="'. t('Google Checkout') .'" title="'. t('Fast checkout through Google.') .'" src="'. $checkout_url .'/buttons/checkout.gif?merchant_id='. $merchant_id .'&w='. $width .'&h='. $height .'&style='. variable_get('uc_google_checkout_button_color', 'trans') .'&variant='. ($disable ? 'disabled' : 'text') .'&loc=en_US" height="'. $height .'" width="'. $width .'" />',
- );
- $form['submit_help'] = array(
- '#value' => '<br /><a href="javascript:void(window.open(\' http://checkout.google.com/seller/what_is_google_checkout.html\',\'whatischeckout\',\'scrollbars=0,resizable=1,directories=0,height=250,width=400\'));" OnMouseOver="return window.status = \''. addslashes(t('What is Google Checkout?')) .'\';" OnMouseOut="return window.status = \'\';">'. addslashes(t('What is Google Checkout?')) .'</a>',
- );
-
- $form['analyticsdata'] = array(
- '#type' => 'hidden',
- '#default_value' => '',
- );
-
- return $form;
- }
-
- /**
- * Form submission handler for uc_google_checkout_cart_form().
- *
- * @see uc_google_checkout_cart_form()
- */
- function uc_google_checkout_cart_form_submit($form, &$form_state) {
- global $user;
- $items = uc_cart_get_contents();
-
- if (!is_array($items) || count($items) == 0) {
- drupal_set_message(t('You do not have any items in your shopping cart.'));
- return;
- }
-
- if (empty($_SESSION['cart_order'])) {
- $order = uc_order_new($user->uid);
- $_SESSION['cart_order'] = $order->order_id;
- }
- else {
- $order = new stdClass();
- $order->uid = $user->uid;
- $order->order_id = $_SESSION['cart_order'];
- $order->primary_email = $user->mail;
- $order->order_status = uc_order_state_default('in_checkout');
- }
-
- $order->products = $items;
- uc_order_save($order);
- uc_order_update_status($order->order_id, 'in_google_checkout');
- $order->order_status = 'in_google_checkout';
-
- $order->analytics_data = $form_state['values']['analyticsdata'];
- $request = uc_google_checkout_cart_request($order);
- if ($response = uc_google_checkout_send_request('merchantCheckout', $request)) {
- $redirect = (string) $response->{'redirect-url'};
- drupal_goto($redirect);
- }
- }
-
- function uc_google_checkout_cart_request($order) {
- if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
- $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
- }
- else {
- $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
- }
-
- $output = '<?xml version="1.0" encoding="UTF-8"?>';
- $output .= "\n";
-
- if (count($order->products)) {
- $output .= '<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">';
- $output .= '<shopping-cart>';
- $output .= '<items>';
- foreach ($order->products as $product) {
- $output .= '<item>';
- $output .= '<item-name>'. check_plain($product->model) .'</item-name>';
- $output .= '<item-description>'. check_plain($product->title) .'</item-description>';
- $output .= '<unit-price currency="'. variable_get('uc_currency_code', 'USD') .'">'. $product->price .'</unit-price>';
- $output .= '<item-weight unit="LB" value="'. $product->weight * uc_weight_conversion($product->weight_units, 'lb') .'" />';
- if (!uc_cart_product_is_shippable($product)) {
- $output .= '<digital-content>';
- $output .= '<display-disposition>PESSIMISTIC</display-disposition>';
- $output .= '<email-delivery>true</email-delivery>';
- $output .= '</digital-content>';
- }
- $output .= '<quantity>'. $product->qty .'</quantity>';
- $output .= '<merchant-item-id>'. $product->nid .'|'. $product->model .'</merchant-item-id>';
- $output .= '</item>';
- }
- $output .= '</items>';
- $output .= '<merchant-private-data>';
- $output .= '<cart-id>'. uc_cart_get_id() .'</cart-id>';
- $output .= '<order-id>'. $order->order_id .'</order-id>';
- $output .= '</merchant-private-data>';
- $output .= '</shopping-cart>';
- $output .= '<checkout-flow-support>';
- $output .= '<merchant-checkout-flow-support>';
-
- if (uc_order_is_shippable($order)) {
- $output .= '<shipping-methods>';
-
- $order->delivery_city = variable_get('uc_google_checkout_delivery_city', '');
- $order->delivery_zone = variable_get('uc_google_checkout_delivery_zone', 0);
- $order->delivery_country = variable_get('uc_google_checkout_delivery_country', 0);
- $order->delivery_postal_code = variable_get('uc_google_checkout_delivery_postal_code', '');
-
- $methods = module_invoke_all('shipping_method');
- module_load_include('inc', 'uc_quote', 'uc_quote.pages');
- $quote_data = _uc_quote_assemble_quotes($order);
- foreach ($quote_data as $method_id => $options) {
- foreach ($options as $accsrl => $data) {
- if (isset($data['rate'])) {
- $output .= '<merchant-calculated-shipping name="'. check_plain($methods[$method_id]['quote']['accessorials'][$accsrl]) .'">';
- $output .= '<price currency="'. variable_get('uc_currency_code', 'USD') .'">'. $data['rate'] .'</price>';
- $output .= '</merchant-calculated-shipping>';
- }
- }
- }
-
- $output .= '</shipping-methods>';
- $output .= '<merchant-calculations>';
- $output .= '<merchant-calculations-url>'. url('google_checkout/calculations', array('absolute' => TRUE)) .'</merchant-calculations-url>';
- $output .= '</merchant-calculations>';
- }
-
- $output .= '<analytics-data>'. $order->analytics_data .'</analytics-data>';
-
- $tax_table = '';
- $result = db_query("SELECT zone, rate, tax_shipping FROM {uc_gc_taxes}");
- while ($tax = db_fetch_object($result)) {
- $tax_table .= '<default-tax-rule>';
- if ($tax->tax_shipping) {
- $tax_table .= '<shipping-taxed>true</shipping-taxed>';
- }
- $tax_table .= '<rate>'. (float)$tax->rate .'</rate>';
-
- $tax_table .= '<tax-area>';
- $tax_table .= '<us-state-area>';
- $tax_table .= '<state>'. $tax->zone .'</state>';
- $tax_table .= '</us-state-area>';
- $tax_table .= '</tax-area>';
-
- $tax_table .= '</default-tax-rule>';
- }
-
- if ($tax_table) {
- $output .= '<tax-tables>';
- $output .= '<default-tax-table>';
- $output .= '<tax-rules>';
- $output .= $tax_table;
- $output .= '</tax-rules>';
- $output .= '</default-tax-table>';
- $output .= '</tax-tables>';
- }
-
- $output .= '<edit-cart-url>'. url('cart', array('absolute' => TRUE)) .'</edit-cart-url>';
- if (($page = variable_get('uc_continue_shopping_url', '')) != '<none>') {
- $output .= '<continue-shopping-url>'. url($page, array('absolute' => TRUE)) .'</continue-shopping-url>';
- }
- $output .= '<platform-id>218752253180456</platform-id>';
- $output .= '</merchant-checkout-flow-support>';
- $output .= '</checkout-flow-support>';
- $output .= '</checkout-shopping-cart>';
- }
-
- return $output;
- }
-
- function uc_google_checkout_headers() {
- if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
- $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
- $merchant_key = variable_get('uc_google_checkout_merchant_key', '');
- }
- else {
- $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
- $merchant_key = variable_get('uc_google_checkout_test_merchant_key', '');
- }
- $headers = array();
- $authorization = $merchant_id .':'. $merchant_key;
- if ($authorization != ':') {
- $headers['Authorization'] = 'Basic '. base64_encode($authorization);
- }
- $headers['Content-Type'] = 'application/xml; charset=UTF-8';
- $headers['Accept'] = 'application/xml; charset=UTF-8';
- return $headers;
- }
-
- function uc_google_checkout_send_request($api, $request) {
- if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
- $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
- $checkout_url = 'https://checkout.google.com';
- }
- else {
- $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
- $checkout_url = 'https://sandbox.google.com/checkout';
- }
-
- // Google's XML parser doesn't like named entities apparently.
- str_replace(array('&', '<', '>'), array('&', '<', '>'), $request);
- $response_obj = drupal_http_request($checkout_url .'/api/checkout/v2/'. $api .'/Merchant/'. $merchant_id, uc_google_checkout_headers(), 'POST', $request);
- if (isset($response_obj->error)) {
- watchdog('google', '@error', array('@error' => $response_obj->error), WATCHDOG_ERROR);
- }
- $response = new SimpleXMLElement($response_obj->data);
- if ($response->getName() == 'error') {
- $error = (string) $response->{'error-message'};
- drupal_set_message($error, 'error');
- watchdog('google', '@error', array('@error' => $error), WATCHDOG_ERROR);
- return NULL;
- }
-
- /**
- * Ugly hack to work around PHP bug, details here:
- * http://bugs.php.net/bug.php?id=23220
- * We strip out errors that look something like:
- * warning: fread() [function.fread]: SSL fatal protocol error in...
- * Copied from http://drupal.org/node/70915.
- */
- $messages = drupal_set_message();
- $errors = isset($messages['error']) ? $messages['error'] : array();
- foreach ($errors as $i => $error) {
- if (strpos($error, 'SSL: fatal protocol error in')) {
- unset($_SESSION['messages']['error'][$i]);
- }
- }
- if (empty($_SESSION['messages']['error'])) {
- unset($_SESSION['messages']['error']);
- }
- db_query("DELETE FROM {watchdog} WHERE type = 'php' AND variables LIKE '%%SSL: fatal protocol error%%'");
- // End of ugly hack.
-
- return $response;
- }
-
- function uc_google_checkout_pane_email_allowed($op, $order) {
- switch ($op) {
- case 'customer':
- case 'view':
- if (isset($order->data['email_allowed']) && $order->data['email_allowed']) {
- $output = t('Customer will accept marketing emails.');
- }
- else {
- $output = t('Customer does not want marketing emails.');
- }
- return $output;
- }
- }
-
- /**
- * Add setting callbacks to the payment settings section
- * The fulfillment sections need coded still. JS.
- */
- function uc_payment_method_google_checkout($op, &$arg1) {
- switch ($op) {
- case 'order-view':
- $output = l(t('Google Checkout terminal'), 'admin/store/orders/'. $arg1->order_id .'/google_checkout');
- return $output;
- case 'settings':
- $form = array();
-
- $form['link'] = array(
- '#value' => l(t('Click here to go to Google Checkout settings.'), 'admin/store/settings/google_checkout'),
- );
-
- return $form;
- }
- }
-
- function uc_google_checkout_new_order($new_order) {
- $order_id = $new_order->{'shopping-cart'}->{'merchant-private-data'}->{'order-id'};
- $cart_id = (string) $new_order->{'shopping-cart'}->{'merchant-private-data'}->{'cart-id'};
-
- $order = uc_order_load($order_id);
- if ($order) {
- $shipping_address = $new_order->{'buyer-shipping-address'};
- $order->delivery_company = (string) $shipping_address->{'company-name'};
- $order->delivery_first_name = (string) $shipping_address->{'structured-name'}->{'first-name'};
- $order->delivery_last_name = (string) $shipping_address->{'structured-name'}->{'last-name'};
- $order->delivery_phone = (string) $shipping_address->phone;
- $order->delivery_street1 = (string) $shipping_address->address1;
- $order->delivery_street2 = (string) $shipping_address->address2;
- $order->delivery_city = (string) $shipping_address->city;
- $zone_id = db_result(db_query("SELECT zone_id FROM {uc_zones} WHERE zone_code = '%s'", $shipping_address->region));
- $order->delivery_zone = $zone_id;
- $countries = uc_get_country_data(array('country_iso_code_2' => $shipping_address->{'country-code'}));
- $order->delivery_country = $countries[0]['country_id'];
- $order->delivery_postal_code = (string) $shipping_address->{'postal-code'};
-
- $billing_address = $new_order->{'buyer-billing-address'};
- $order->billing_company = (string) $billing_address->{'company-name'};
- $order->billing_first_name = (string) $billing_address->{'structured-name'}->{'first-name'};
- $order->billing_last_name = (string) $billing_address->{'structured-name'}->{'last-name'};
- $order->billing_phone = (string) $billing_address->phone;
- $order->billing_street1 = (string) $billing_address->address1;
- $order->billing_street2 = (string) $billing_address->address2;
- $order->billing_city = (string) $billing_address->city;
- if ($billing_address['region'] != $shipping_address->region) {
- $zone_id = db_result(db_query("SELECT zone_id FROM {uc_zones} WHERE zone_code = '%s'", $billing_address->region));
- }
- $order->billing_zone = $zone_id;
- if ($billing_address->{'country-code'} != $shipping_address->{'country-code'}) {
- $countries = uc_get_country_data(array('country_iso_code_2' => $billing_address->{'country-code'}));
- }
- $order->billing_country = $countries[0]['country_id'];
- $order->billing_postal_code = (string) $billing_address->{'postal-code'};
-
- if (!$order->primary_email) {
- $order->primary_email = (string) $billing_address->email;
- }
-
- if ($new_order->{'buyer-marketing-preferences'}->{'email-allowed'} == 'true') {
- $order->data['email_allowed'] = TRUE;
- if (module_exists('simplenews')) {
- simplenews_subscribe_user($order->primary_email, variable_get('uc_google_checkout_simplenews_tid', 0), TRUE);
- }
- }
- else {
- $order->data['email_allowed'] = FALSE;
- if (module_exists('simplenews')) {
- simplenews_unsubscribe_user($order->primary_email, variable_get('uc_google_checkout_simplenews_tid', 0), FALSE);
- }
- }
-
- $order->payment_method = 'google_checkout';
-
- $comments = array();
-
- // Ubercart should already be set up to calculate taxes itself.
- //uc_order_line_item_add($order_id, 'tax', t('Total tax'), $new_order->{'order-adjustment'}->{'total-tax'});
- if (isset($new_order->{'order-adjustment'}->shipping)) {
- $shipping_line = $new_order->{'order-adjustment'}->shipping[0];
- if ($shipping_line->{'shipping-cost'}) {
- $shipping = array(
- 'name' => check_plain($shipping_line->{'shipping-name'}),
- 'cost' => $shipping_line->{'shipping-cost'},
- );
- }
- elseif ($shipping_line->{'carrier-calculated-shipping-adjustment'}->{'shipping-cost'}) {
- $shipping = array(
- 'name' => check_plain($shipping_line->{'carrier-calculated-shipping-adjustment'}->{'shipping-name'}),
- 'cost' => $shipping_line->{'carrier-calculated-shipping-adjustment'}->{'shipping-cost'},
- );
- }
- elseif ($shipping_line->{'merchant-calculated-shipping-adjustment'}->{'shipping-cost'}) {
- $shipping = array(
- 'name' => check_plain($shipping_line->{'merchant-calculated-shipping-adjustment'}->{'shipping-name'}),
- 'cost' => $shipping_line->{'merchant-calculated-shipping-adjustment'}->{'shipping-cost'},
- );
- }
- uc_order_line_item_add($order_id, 'shipping', $shipping['name'], $shipping['cost']);
- }
- if (isset($new_order->{'order-adjustment'}->{'merchant-codes'})) {
- foreach ($new_order->{'order-adjustment'}->{'merchant-codes'}->children() as $adjustment) {
- $type = $adjustment->getName();
- if ($type == 'coupon-adjustment') {
- uc_order_line_item_add($order_id, 'gc_coupon', check_plain((string) $adjustment->code), -((string) $adjustment->{'applied-amount'}));
- $comments[] = check_plain((string) $adjustment->message);
- }
- elseif ($type == 'gift-certificate-adjustment') {
- uc_order_line_item_add($order_id, 'gc_gift_certificate', check_plain((string) $adjustment->code), -((string) $adjustment->{'applied-amount'}));
- $comments[] = check_plain((string) $adjustment->message);
- }
- }
- }
-
- uc_order_save($order);
-
- uc_cart_complete_sale($order);
- // uc_cart_complete_sale() empties the current cart (Google Checkout
- // API's cart) so we must empty the customer's manually.
- uc_cart_empty($cart_id);
- // Add a comment to let sales team know this came in through the site.
- if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
- $checkout_url = 'https://checkout.google.com';
- }
- else {
- $checkout_url = 'https://sandbox.google.com/checkout';
- }
- uc_order_comment_save($order->order_id, 0, t('Order created through Google Checkout (#@gco_order).', array('@gco_order' => l($new_order->{'google-order-number'}, $checkout_url .'/sell/multiOrder', array('query' => array('order' => (string) $new_order->{'google-order-number'}), 'external' => TRUE)))), 'admin');
-
- // uc_cart_complete_sale() also unsets some $_SESSION variables. These
- // are tied to the user-id, so we record that for when they log in later.
- $users = variable_get('uc_google_checkout_order_users', array());
- $users[$order->uid] = $order->uid;
- variable_set('uc_google_checkout_order_users', $users);
-
- // Add messages from order adjustments (coupons, gift certificates, etc.).
- foreach ($comments as $comment) {
- $comment = trim($comment);
- if ($comment) {
- uc_order_comment_save($order->order_id, 0, $comment, 'order', $order->order_status, 0);
- }
- }
-
- db_query("INSERT INTO {uc_gc_orders} (order_id, gc_order_number, gc_total) VALUES (%d, '%s', %f)", $order_id, $new_order->{'google-order-number'}, $new_order->{'order-total'});
-
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- function uc_google_checkout_accept_risk($risk) {
- $order_id = uc_google_checkout_get_order($risk->{'google-order-number'});
- if ($order_id) {
- $risk_info = $risk->{'risk-information'};
- $assessment = t('Risk information notification:') .'<br />';
- $avs_response = $risk_info->{'avs-response'};
- switch ($avs_response) {
- case 'Y':
- $assessment .= t('- Full AVS match (address and postal code)');
- break;
- case 'P':
- $assessment .= t('- Partial AVS match (postal code only)');
- break;
- case 'A':
- $assessment .= t('- Partial AVS match (address only)');
- break;
- case 'N':
- $assessment .= t('- No AVS match');
- break;
- case 'U':
- $assessment .= t('- AVS not supported by issuer');
- break;
- default:
- $assessment .= t('<b>Error:</b> No AVS response.');
- break;
- }
- $assessment .= '<br />';
-
- $cvn_response = $risk_info->{'cvn-response'};
- switch ($cvn_response) {
- case 'M':
- $assessment .= t('- CVN match');
- break;
- case 'N':
- $assessment .= t('- No CVN match');
- break;
- case 'U':
- $assessment .= t('- CVN not available');
- break;
- case 'E':
- $assessment .= t('- CVN error');
- break;
- default:
- $assessment .= t('<b>Error:</b> No CVN response.');
- break;
- }
- $assessment .= '<br />';
- $assessment .= t('Partial CC number: %s', array('%s' => $risk_info->{'partial-cc-number'}));
- $assessment .= '<br />';
- $assessment .= format_plural($risk_info->{'buyer-account-age'}, 'Google Checkout member for @count day.', 'Google Checkout member for @count days.');
- $assessment .= '<br />';
- $assessment .= t('Eligible for protection: <strong>@bool</strong>', array('@bool' => drupal_strtoupper($risk_info->{'eligible-for-protection'})));
- uc_order_comment_save($order_id, 0, $assessment, 'admin', 'chargeable');
-
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- function uc_google_checkout_order_state_change($change) {
- $order_id = uc_google_checkout_get_order($change->{'google-order-number'});
- if ($order_id) {
- $new_financial = (string) $change->{'new-financial-order-state'};
- $new_fulfillment = (string) $change->{'new-fulfillment-order-state'};
- $prev_financial = (string) $change->{'previous-financial-order-state'};
- $prev_fulfillment = (string) $change->{'previous-fulfillment-order-state'};
- db_query("UPDATE {uc_gc_orders} SET financial_state = '%s', fulfillment_state = '%s' WHERE order_id = %d AND financial_state = '%s' AND fulfillment_state = '%s'", array($new_financial, $new_fulfillment, $order_id, $prev_financial, $prev_fulfillment));
- if ($new_financial != $prev_financial) {
- $_SESSION['google_updates'] = TRUE;
- switch ($new_financial) {
- case 'CHARGEABLE':
- uc_order_update_status($order_id, 'chargeable');
- break;
- case 'CHARGING':
- watchdog('google', 'Charging @order_id', array('@order_id' => $order_id));
- break;
- case 'CHARGED':
- watchdog('google', 'Charged @order_id', array('@order_id' => $order_id));
- break;
- case 'PAYMENT_DECLINED':
- watchdog('google', 'Payment declined @order_id', array('@order_id' => $order_id));
- break;
- case 'CANCELLED_BY_GOOGLE':
- $message = t('Order %order canceled by Google: %reason', array('%order' => $order_id, '%reason' => $change->reason));
- uc_order_comment_save($order_id, 0, $message, 'admin', 'canceled');
- case 'CANCELLED':
- uc_order_comment_save($order_id, 0, t('Order canceled.'), 'order', 'canceled');
- uc_order_update_status($order_id, 'canceled');
- break;
- default:
-
- break;
- }
- unset($_SESSION['google_updates']);
- }
- elseif ($new_fulfillment != $prev_fulfillment) {
- $_SESSION['google_updates'] = TRUE;
- switch ($new_fulfillment) {
- case 'PROCESSING':
- watchdog('google', 'Processing @order_id', array('@order_id' => $order_id));
- break;
- case 'DELIVERED':
- uc_order_update_status($order_id, 'completed');
- watchdog('google', 'Delivered @order_id', array('@order_id' => $order_id));
- break;
- case 'WILL_NOT_DELIVER':
- watchdog('google', 'Will not deliver @order_id', array('@order_id' => $order_id));
- break;
- }
- unset($_SESSION['google_updates']);
- }
-
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- function uc_google_checkout_authorize_amount($auth) {
- global $user;
-
- $order_id = uc_google_checkout_get_order($auth->{'google-order-number'});
- if ($order_id) {
- $_SESSION['google_updates'] = TRUE;
-
- uc_order_update_status($order_id, 'chargeable');
-
- unset($_SESSION['google_updates']);
-
- $o_comment = t('<b>Authorization:</b> @amount', array('@amount' => uc_currency_format((string) $auth->{'authorization-amount'})));
- uc_order_comment_save($order_id, $user->uid, $o_comment);
-
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- function uc_google_checkout_charge($order_id, $amount) {
- $google_order_number = uc_google_checkout_get_google_number($order_id);
- $output = '';
-
- $output .= '<?xml version="1.0" encoding="UTF-8"?>';
- $output .= "\n";
- $output .= '<charge-and-ship-order xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
- $output .= '<amount currency="'. variable_get('uc_currency_code', 'USD') .'">'. $amount .'</amount>';
- $output .= '</charge-and-ship-order>';
-
- if ($response = uc_google_checkout_send_request('request', $output)) {
- if (!uc_google_checkout_charge_order($response)) {
- drupal_set_message(t('Charge request sent to Google Checkout. The charge confirmation should appear on this page momentarily.'));
- }
- }
- return 'admin/store/orders/'. $order_id;
- }
-
- function uc_google_checkout_charge_order($charge) {
- $order_id = uc_google_checkout_get_order($charge->{'google-order-number'});
- if ($order_id) {
- $amount = (string) $charge->{'latest-charge-amount'};
- uc_payment_enter($order_id, 'google_checkout', $amount, 0,
- '', t('Payment received by Google Checkout'));
- $context = array(
- 'revision' => 'formatted-original',
- 'type' => 'amount',
- );
- uc_order_comment_save($order_id, 0, t('Payment of %amount received by Google Checkout.', array('%amount' => uc_price($amount, $context))), 'admin', 'chargeable');
-
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- function uc_google_checkout_refund($order_id, $amount, $reason, $comment = '') {
- $google_order_number = uc_google_checkout_get_google_number($order_id);
- $output = '';
-
- $output .= '<?xml version="1.0" encoding="UTF-8"?>';
- $output .= "\n";
- $output .= '<refund-order xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
- $output .= '<amount currency="'. variable_get('uc_currency_code', 'USD') .'">'. $amount .'</amount>';
- $output .= '<comment>'. check_plain($comment) .'</comment>';
- $output .= '<reason>'. check_plain($reason) .'</reason>';
- $output .= '</refund-order>';
-
- if ($response = uc_google_checkout_send_request('request', $output)) {
- if (!uc_google_checkout_refund_order($response)) {
- drupal_set_message(t('Refund request sent to Google Checkout. The refund confirmation should appear on this page momentarily.'));
- }
- }
- return 'admin/store/orders/'. $order_id;
- }
-
- function uc_google_checkout_refund_order($refund) {
- $order_id = uc_google_checkout_get_order($refund->{'google-order-number'});
- if ($order_id) {
- uc_payment_enter($order_id, 'google_checkout', -((string) $refund->{'latest-refund-amount'}),
- 0, '', t('Refund received by Google Checkout'));
- $context = array(
- 'revision' => 'formatted-original',
- 'type' => 'amount',
- );
- uc_order_comment_save($order_id, 0, t('Refund of %amount received by Google Checkout.', array('%amount' => uc_price((string) $refund->{'latest-refund-amount'}, $context))), 'admin', 'processing');
-
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- function uc_google_checkout_notify_update($form, &$form_state) {
- $order = uc_order_load($form_state['values']['order_id']);
- if ($order !== FALSE && isset($order->google_order_number) && isset($form_state['values']['order_comment']) && drupal_strlen($form_state['values']['order_comment'])) {
- $request = uc_google_checkout_buyer_message_request($form_state['values']['order_id'], $form_state['values']['order_comment']);
- $response = uc_google_checkout_send_request('request', $request);
- }
- }
-
- function uc_google_checkout_buyer_message_request($order_id, $message) {
- $google_order_number = uc_google_checkout_get_google_number($order_id);
- $output = '<?xml version="1.0" encoding="UTF-8"?>';
- $output .= "\n";
- $output .= '<send-buyer-message xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
- $output .= '<message>'. check_plain($message) .'</message>';
- $output .= '<send-email>true</send-email>';
- $output .= '</send-buyer-message>';
-
- return $output;
- }
-
- function uc_google_checkout_cancel_order($order) {
- $request = '<?xml version="1.0" encoding="UTF-8"?>';
- $request .= "\n";
- $request .= '<cancel-order xmlns="http://checkout.google.com/schema/2" google-order-number="'. $order->google_order_number .'">';
- $request .= '<reason>'. token_replace_multiple(variable_get('uc_google_checkout_order_cancel_reason', t('Order canceled. See order comments at [order-url] for more information.')), array('global' => NULL, 'order' => $order)) .'</reason>';
- $request .= '</cancel-order>';
-
- if ($response = uc_google_checkout_send_request('request', $request)) {
- return TRUE;
- }
- else {
- return FALSE;
- }
- }
-
- function uc_google_checkout_notification_acknowledgement($serial_number) {
- drupal_set_header('HTTP/1.1 200 OK');
- print '<?xml version="1.0" encoding="UTF-8"?>';
- print "\n";
- print '<notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number="'. $serial_number .'" />';
- exit();
- }
-
- function uc_google_checkout_notification_error($message = NULL) {
- if (is_null($message)) {
- $message = t('Unknown order id or malformed XML.');
- }
- drupal_set_header('HTTP/1.1 400 Bad Request');
- watchdog('google', '!message', array('!message' => $message), WATCHDOG_ERROR);
- exit();
- }
-
- function uc_google_checkout_get_order($google_order_number) {
- return db_result(db_query("SELECT order_id FROM {uc_gc_orders} WHERE gc_order_number = '%s'", $google_order_number));
- }
-
- function uc_google_checkout_get_google_number($order_id) {
- return db_result(db_query("SELECT gc_order_number FROM {uc_gc_orders} WHERE order_id = %d", $order_id));
- }
-
- function uc_google_checkout_shipping_services() {
- return array_merge(uc_google_checkout_fedex_services(), uc_google_checkout_ups_services(), uc_google_checkout_usps_services());
- }
-
- function uc_google_checkout_fedex_services() {
- return array(
- 'fedex_ground' => 'Ground',
- 'fedex_home' => 'Home Delivery',
- 'fedex_express' => 'Express Saver',
- 'fedex_first' => 'First Overnight',
- 'fedex_priority' => 'Priority Overnight',
- 'fedex_standard' => 'Standard Overnight',
- 'fedex_2day' => '2Day',
- );
- }
-
- function uc_google_checkout_ups_services() {
- return array(
- 'ups_next_day' => 'Next Day Air',
- 'ups_next_day_am' => 'Next Day Air Early AM',
- 'ups_next_day_saver' => 'Next Day Air Saver',
- 'ups_2nd_day' => '2nd Day Air',
- 'ups_2nd_day_am' => '2nd Day Air AM',
- 'ups_3_day' => '3 Day Select',
- 'ups_ground' => 'Ground',
- );
- }
-
- function uc_google_checkout_usps_services() {
- return array(
- 'usps_express' => 'Express Mail',
- 'usps_priority' => 'Priority Mail',
- 'usps_parcel' => 'Parcel Post',
- 'usps_media' => 'Media Mail',
- );
- }
-
- function uc_google_checkout_shipping_companies() {
- return array(
- 'fedex' => 'FedEx',
- 'ups' => 'UPS',
- 'usps' => 'USPS',
- );
- }
-
- /**
- * Returns an array of options for the currency selection widget.
- */
- function _uc_google_checkout_currency_codes() {
- return drupal_map_assoc(array('AUD', 'CAD', 'EUR', 'GBP', 'HKD', 'JPY', 'USD'));
- }
-
- function uc_google_checkout_avs_code($code = NULL) {
- $codes = array(
- 'Y' => t('Full AVS match (address and postal code)'),
- 'P' => t('Partial AVS match (postal code only)'),
- 'A' => t('Partial AVS match (address only)'),
- 'N' => t('No AVS match'),
- 'U' => t('AVS not supported by issuer'),
- );
-
- if ($code) {
- return isset($codes[$code]) ? $codes[$code] : '';
- }
- else {
- return $codes;
- }
- }
-
- function uc_google_checkout_cvn_code($code = NULL) {
- $codes = array(
- 'M' => t('CVN match'),
- 'N' => t('No CVN match'),
- 'U' => t('CVN not available'),
- 'E' => t('CVN error'),
- );
-
- if ($code) {
- return isset($codes[$code]) ? $codes[$code] : '';
- }
- else {
- return $codes;
- }
- }
-