=== modified file 'payment/uc_google_checkout/uc_google_checkout.module'
--- payment/uc_google_checkout/uc_google_checkout.module	2010-10-19 19:57:18 +0000
+++ payment/uc_google_checkout/uc_google_checkout.module	2011-02-15 18:30:30 +0000
@@ -349,8 +349,9 @@
         $request .= '</item-ids>';
         $request .= '<send-email>false</send-email>';
         $request .= '</reset-items-shipping-information>';
+
+        $response = uc_google_checkout_send_request('request', $request);
       }
-      $response = uc_google_checkout_send_request('request', $request);
     break;
   }
 }
@@ -752,21 +753,22 @@
 
     $comments = array();
 
-    uc_order_line_item_add($order_id, 'tax', t('Total tax'), $new_order->{'order-adjustment'}->{'total-tax'});
+    // 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];
-      uc_order_line_item_add($order_id, 'shipping', check_plain($shipping_line->{'shipping-name'}), $shipping_line->{'shipping-cost'});
+      uc_order_line_item_add($order_id, 'shipping', check_plain((string) $shipping_line->{'shipping-name'}), (string) $shipping_line->{'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($adjustment->code), -$adjustment->{'applied-amount'});
-          $comments[] = check_plain($adjustment->message);
+          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($adjustment->code), -($adjustment->{'applied-amount'}));
-          $comments[] = check_plain($adjustment->message);
+          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);
         }
       }
     }
@@ -778,7 +780,13 @@
     // 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.
-    uc_order_comment_save($order->order_id, 0, t('Order created through Google Checkout (#@gco_order).', array('@gco_order' => $new_order->{'google-order-number'})), 'admin');
+    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' => $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.
@@ -796,10 +804,10 @@
 
     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'});
 
-    uc_google_checkout_notification_acknowledgement($new_order['serial-number']);
+    return TRUE;
   }
   else {
-    uc_google_checkout_notification_error();
+    return FALSE;
   }
 }
 
@@ -852,11 +860,15 @@
     $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 month.', 'Google Checkout member for @count months.');
+    $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');
-    uc_google_checkout_notification_acknowledgement($risk['serial-number']);
+
+    return TRUE;
+  }
+  else {
+    return FALSE;
   }
 }
 
@@ -912,10 +924,32 @@
       }
       unset($_SESSION['google_updates']);
     }
-    uc_google_checkout_notification_acknowledgement($change['serial-number']);
-  }
-  else {
-    uc_google_checkout_notification_error();
+
+    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;
   }
 }
 
@@ -925,12 +959,14 @@
 
   $output .= '<?xml version="1.0" encoding="UTF-8"?>';
   $output .= "\n";
-  $output .= '<charge-order xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
+  $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-order>';
+  $output .= '</charge-and-ship-order>';
 
   if ($response = uc_google_checkout_send_request('request', $output)) {
-    drupal_set_message(t('Charge request sent to Google Checkout. The charge confirmation should appear on this page momentarily.'));
+    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;
 }
@@ -946,10 +982,11 @@
       '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');
-    uc_google_checkout_notification_acknowledgement($charge['serial-number']);
+
+    return TRUE;
   }
   else {
-    uc_google_checkout_notification_error();
+    return FALSE;
   }
 }
 
@@ -966,7 +1003,9 @@
   $output .= '</refund-order>';
 
   if ($response = uc_google_checkout_send_request('request', $output)) {
-    drupal_set_message(t('Refund request sent to Google Checkout. The refund confirmation should appear on this page momentarily.'));
+    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;
 }
@@ -974,30 +1013,31 @@
 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', -$refund->{'latest-refund-amount'},
+    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($refund->{'latest-refund-amount'}, $context))),
-                          'admin', 'processing');
-    uc_google_checkout_notification_acknowledgement($refund['serial-number']);
+    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 {
-    uc_google_checkout_notification_error();
+    return FALSE;
   }
 }
 
 function uc_google_checkout_notify_update($form, &$form_state) {
   $order = uc_order_load($form_state['values']['order_id']);
-  if ($order !== FALSE && $order->google_order_number && isset($form_state['values']['order_comment']) && drupal_strlen($form_state['values']['order_comment'])) {
-    $request = uc_google_checkout_buyer_message_request($order->google_order_number, $form_state['values']['order_comment']);
+  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($google_order_number, $message) {
+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 .'">';
@@ -1099,3 +1139,36 @@
 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;
+  }
+}

=== modified file 'payment/uc_google_checkout/uc_google_checkout.pages.inc'
--- payment/uc_google_checkout/uc_google_checkout.pages.inc	2010-08-11 17:28:06 +0000
+++ payment/uc_google_checkout/uc_google_checkout.pages.inc	2011-02-15 18:30:21 +0000
@@ -8,6 +8,52 @@
  */
 
 function uc_google_checkout_callback() {
+  if (isset($_POST['serial-number'])) {
+    $request = '<?xml version="1.0" encoding="UTF-8"?>';
+    $request .= "\n";
+    $request .= '<notification-history-request xmlns="http://checkout.google.com/schema/2">';
+    $request .= '<serial-number>'. check_plain($_POST['serial-number']) .'</serial-number>';
+    $request .= '</notification-history-request>';
+
+    if ($response = uc_google_checkout_send_request('reports', $request)) {
+      watchdog('google', 'Notification document: @xml', array('@xml' => $response->asXML()), WATCHDOG_DEBUG);
+      switch ($response->getName()) {
+        case 'new-order-notification':
+          $success = uc_google_checkout_new_order($response);
+        break;
+        case 'order-state-change-notification':
+          $success = uc_google_checkout_order_state_change($response);
+        break;
+        case 'risk-information-notification':
+          $success = uc_google_checkout_accept_risk($response);
+        break;
+        case 'authorization-amount-notification':
+          $success = uc_google_checkout_authorize_amount($response);
+        break;
+        case 'charge-amount-notification':
+          $success = uc_google_checkout_charge_order($response);
+        break;
+        case 'refund-amount-notification':
+          $success = uc_google_checkout_refund_order($response);
+        break;
+        default:
+          $success = TRUE;
+        break;
+      }
+
+      if ($success) {
+        uc_google_checkout_notification_acknowledgement($_POST['serial-number']);
+      }
+    }
+
+    uc_google_checkout_notification_error();
+  }
+
+  return MENU_NOT_FOUND;
+}
+
+function uc_google_checkout_merchant_calculation() {
+  // Error checking.
   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', '');
@@ -22,30 +68,72 @@
     watchdog('google', 'HTTP Authorization header does not match settings.', array(), WATCHDOG_ERROR);
     return MENU_ACCESS_DENIED;
   }
+
   $input = file_get_contents('php://input');
-  //watchdog('google', print_r(check_plain($input), TRUE), NULL, WATCHDOG_NOTICE);
-  $xml = new SimpleXMLElement($input);
-  switch ($xml->getName()) {
-    case 'merchant-calculation-callback':
-      //uc_google_checkout_merchant_calculation($xml);
-    break;
-    case 'new-order-notification':
-      uc_google_checkout_new_order($xml);
-    break;
-    case 'order-state-change-notification':
-      uc_google_checkout_order_state_change($xml);
-    break;
-    case 'risk-information-notification':
-      uc_google_checkout_accept_risk($xml);
-    break;
-    case 'charge-amount-notification':
-      uc_google_checkout_charge_order($xml);
-    break;
-    case 'refund-amount-notification':
-      uc_google_checkout_refund_order($xml);
-    break;
-    default:
-      watchdog('google', 'Unknown notification document: @xml', array('@xml' => $input), WATCHDOG_ERROR);
-      $output = uc_google_checkout_notification_acknowledgement($xml->{'serial-number'});
-  }
+  $calc = new SimpleXMLElement($input);
+
+  if ($calc->getName() != 'merchant-calculation-callback') {
+    uc_google_checkout_notification_error();
+  }
+
+  $order = new stdClass();
+  $order->uid = 0;
+
+  $products = array();
+  foreach ($calc->{'shopping-cart'}->items->item as $item) {
+    list($nid, $model) = explode('|', $item->{'merchant-item-id'});
+    $node = node_load($nid);
+    $node->model = (string) $item->{'item-name'};
+    $node->title = (string) $item->{'item-description'};
+    $node->price = (string) $item->{'unit-price'};
+    $node->qty = (string) $item->quantity;
+    $node->weight = (string) $item->{'item-weight'};
+
+    $products[] = $node;
+  }
+
+  $order->products = $products;
+
+  $address = $calc->calculate->addresses->{'anonymous-address'};
+
+  $country = uc_get_country_data(array('country_iso_code_2' => $address->{'country-code'}));
+  $order->delivery_country = $country[0]['country_id'];
+  $order->delivery_city = $address->city;
+  $zone_id = db_result(db_query("SELECT zone_id FROM {uc_zones} WHERE zone_code = '%s' AND zone_country_id = %d", $address->region, $order->delivery_country));
+  $order->delivery_zone = $zone_id;
+  $order->delivery_postal_code = $address->{'postal-code'};
+
+  $order->order_total = uc_order_get_total($order, TRUE);
+
+  $methods = module_invoke_all('shipping_method');
+  module_load_include('inc', 'uc_quote', 'uc_quote.pages');
+  $quote_data = _uc_quote_assemble_quotes($order);
+  $results = '';
+  foreach ($quote_data as $method_id => $options) {
+    foreach ($options as $accsrl => $data) {
+      $results .= '<result shipping-name="'. $methods[$method_id]['quote']['accessorials'][$accsrl] .'" address-id="'. $address['id'] .'">';
+
+      $results .= '<shipping-rate currency="'. variable_get('uc_currency_code', 'USD') .'">'. $data['rate'] .'</shipping-rate>';
+      $results .= '<shippable>true</shippable>';
+
+      $results .= '</result>';
+    }
+  }
+
+  if ($results) {
+    $response = '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
+    $response .= '<merchant-calculation-results xmlns="http://checkout.google.com/schema/2">';
+    $response .= '<results>';
+    $response .= $results;
+    $response .= '</results>';
+    $response .= '</merchant-calculation-results>';
+
+    drupal_set_header('HTTP/1.1 200 OK');
+    print $response;
+    exit();
+  }
+
+  drupal_set_header('HTTP/1.1 204 No Content');
+  exit();
+  // So there!
 }

