uc_google_checkout.module

Tracking 6.x-2.x branch
  1. drupal
    1. 6 contributions/ubercart/payment/uc_google_checkout/uc_google_checkout.module
    2. 7 contributions/ubercart/payment/uc_google_checkout/uc_google_checkout.module

Use Google Checkout to collect payment and process orders.

Functions & methods

NameDescription
uc_google_checkout_accept_risk
uc_google_checkout_authorize_amount
uc_google_checkout_avs_code
uc_google_checkout_buyer_message_request
uc_google_checkout_cancel_order
uc_google_checkout_cart_formForm builder for uc_google_checkout_cart_form().
uc_google_checkout_cart_form_submitForm submission handler for uc_google_checkout_cart_form().
uc_google_checkout_cart_paneImplements hook_cart_pane().
uc_google_checkout_cart_request
uc_google_checkout_charge
uc_google_checkout_charge_order
uc_google_checkout_cvn_code
uc_google_checkout_fedex_services
uc_google_checkout_form_alterImplements hook_form_alter().
uc_google_checkout_get_google_number
uc_google_checkout_get_order
uc_google_checkout_headers
uc_google_checkout_helpImplements hook_help().
uc_google_checkout_initImplements hook_init().
uc_google_checkout_line_itemImplements hook_line_item().
uc_google_checkout_menuImplements hook_menu().
uc_google_checkout_new_order
uc_google_checkout_nodeapiImplements hook_nodeapi().
uc_google_checkout_notification_acknowledgement
uc_google_checkout_notification_error
uc_google_checkout_notify_update
uc_google_checkout_orderImplements hook_order().
uc_google_checkout_order_paneImplements hook_order_pane().
uc_google_checkout_order_state_change
uc_google_checkout_pane_email_allowed
uc_google_checkout_payment_gatewayImplements hook_payment_gateway().
uc_google_checkout_payment_methodImplements hook_payment_method().
uc_google_checkout_refund
uc_google_checkout_refund_order
uc_google_checkout_send_request
uc_google_checkout_shipmentImplements hook_shipment().
uc_google_checkout_shipping_companies
uc_google_checkout_shipping_services
uc_google_checkout_terminal_titleMenu title callback function.
uc_google_checkout_themeImplements hook_theme().
uc_google_checkout_ups_services
uc_google_checkout_usps_services
uc_payment_method_google_checkoutAdd setting callbacks to the payment settings section The fulfillment sections need coded still. JS.
_uc_google_checkout_currency_codesReturns an array of options for the currency selection widget.

File

View source
  1. <?php
  2. /**
  3. * @file
  4. * Use Google Checkout to collect payment and process orders.
  5. */
  6. /******************************************************************************
  7. * Drupal hooks *
  8. ******************************************************************************/
  9. /**
  10. * Implements hook_help().
  11. */
  12. function uc_google_checkout_help($page, $args) {
  13. $output = '';
  14. switch ($page) {
  15. case 'admin/store/settings/google_checkout':
  16. if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
  17. $checkout_url = 'http://checkout.google.com';
  18. }
  19. else {
  20. $checkout_url = 'http://sandbox.google.com/checkout';
  21. }
  22. $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))));
  23. break;
  24. }
  25. return $output;
  26. }
  27. /**
  28. * Implements hook_menu().
  29. */
  30. function uc_google_checkout_menu() {
  31. $items = array();
  32. $items['admin/store/settings/google_checkout'] = array(
  33. 'title' => 'Google Checkout settings',
  34. 'description' => 'Set merchant ID and key for Google Checkout.',
  35. 'page callback' => 'drupal_get_form',
  36. 'page arguments' => array('uc_google_checkout_settings'),
  37. 'access arguments' => array('administer store'),
  38. 'type' => MENU_NORMAL_ITEM,
  39. 'file' => 'uc_google_checkout.admin.inc',
  40. );
  41. $items['admin/store/settings/google_checkout/account'] = array(
  42. 'title' => 'Account',
  43. 'type' => MENU_DEFAULT_LOCAL_TASK,
  44. );
  45. $items['admin/store/settings/google_checkout/shipping'] = array(
  46. 'title' => 'Shipping',
  47. 'description' => 'Calculate shipping charges for orders through Google Checkout.',
  48. 'page callback' => 'drupal_get_form',
  49. 'page arguments' => array('uc_google_checkout_shipping_settings'),
  50. 'access arguments' => array('administer store'),
  51. 'type' => MENU_LOCAL_TASK,
  52. 'file' => 'uc_google_checkout.admin.inc',
  53. );
  54. $items['admin/store/settings/google_checkout/taxes'] = array(
  55. 'title' => 'Taxes',
  56. 'description' => 'Calculate taxes for orders through Google Checkout.',
  57. 'page callback' => 'drupal_get_form',
  58. 'page arguments' => array('uc_google_checkout_taxes_settings'),
  59. 'access arguments' => array('administer store'),
  60. 'type' => MENU_LOCAL_TASK,
  61. 'file' => 'uc_google_checkout.admin.inc',
  62. );
  63. $items['google_checkout'] = array(
  64. 'page callback' => 'uc_google_checkout_callback',
  65. 'access callback' => TRUE,
  66. 'type' => MENU_CALLBACK,
  67. 'file' => 'uc_google_checkout.pages.inc',
  68. );
  69. $items['google_checkout/calculations'] = array(
  70. 'page callback' => 'uc_google_checkout_merchant_calculation',
  71. 'access callback' => TRUE,
  72. 'type' => MENU_CALLBACK,
  73. 'file' => 'uc_google_checkout.pages.inc',
  74. );
  75. $items['admin/store/orders/%uc_order/google_checkout'] = array(
  76. 'title callback' => 'uc_google_checkout_terminal_title',
  77. 'title arguments' => array(3),
  78. 'description' => 'Process a credit card payment or refund through Google Checkout.',
  79. 'page callback' => 'uc_google_checkout_terminal',
  80. 'page arguments' => array(3),
  81. 'access arguments' => array('manual payments'),
  82. 'type' => MENU_CALLBACK,
  83. 'file' => 'uc_google_checkout.admin.inc',
  84. );
  85. return $items;
  86. }
  87. /**
  88. * Menu title callback function.
  89. */
  90. function uc_google_checkout_terminal_title($order) {
  91. return t('Google Checkout terminal: Order @order_id', array('@order_id' => $order->order_id));
  92. }
  93. /**
  94. * Implements hook_init().
  95. */
  96. function uc_google_checkout_init() {
  97. // When an order comes in from Google Checkout, we need to unset some
  98. // $_SESSION data. Since this isn't done under the customer's user, we
  99. // do it when they next load a page.
  100. global $user;
  101. $users = variable_get('uc_google_checkout_order_users', array());
  102. if (isset($users[$user->uid])) {
  103. unset($_SESSION['cart_order'], $_SESSION['do_complete'], $users[$user->uid]);
  104. variable_set('uc_google_checkout_order_users', $users);
  105. }
  106. global $conf;
  107. $conf['i18n_variables'][] = 'uc_google_checkout_order_cancel_reason';
  108. $id = variable_get('googleanalytics_account', '');
  109. if (module_exists('googleanalytics') && !empty($id) && _googleanalytics_visibility_pages() && _googleanalytics_visibility_user($user)) {
  110. $scope = variable_get('googleanalytics_js_scope', 'footer');
  111. 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);
  112. }
  113. }
  114. /**
  115. * Implements hook_theme().
  116. */
  117. function uc_google_checkout_theme() {
  118. return array(
  119. 'uc_google_checkout_shipping_settings' => array(
  120. 'arguments' => array('form' => NULL),
  121. 'file' => 'uc_google_checkout.admin.inc',
  122. ),
  123. 'uc_google_checkout_taxes_settings' => array(
  124. 'arguments' => array('form' => NULL),
  125. 'file' => 'uc_google_checkout.admin.inc',
  126. ),
  127. );
  128. }
  129. /**
  130. * Implements hook_form_alter().
  131. */
  132. function uc_google_checkout_form_alter(&$form, $form_state, $form_id) {
  133. if (uc_product_is_product_form($form)) {
  134. $node = $form['#node'];
  135. if (is_object($node) && $form_id == $node->type .'_node_form' && uc_product_is_product($node->type)) {
  136. $policy_url = 'https://checkout.google.com/support/sell/bin/answer.py?answer=75724';
  137. $form['google_checkout'] = array(
  138. '#type' => 'fieldset',
  139. '#title' => t('Google Checkout settings'),
  140. '#collapsible' => TRUE,
  141. '#collapsed' => TRUE,
  142. );
  143. $form['google_checkout']['gc_salable'] = array(
  144. '#type' => 'checkbox',
  145. '#title' => t('Conforms to Google Checkout content policies.'),
  146. '#default_value' => isset($node->gc_salable) ? $node->gc_salable : TRUE,
  147. '#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)),
  148. );
  149. }
  150. }
  151. elseif ($form_id == 'uc_payment_methods_form') {
  152. // Make sure no one enables this for Ubercart checkout.
  153. $form['pmtable']['google_checkout']['uc_payment_method_google_checkout_checkout']['#disabled'] = TRUE;
  154. $form['pmtable']['google_checkout']['uc_payment_method_google_checkout_checkout']['#value'] = FALSE;
  155. }
  156. elseif ($form_id == 'uc_payment_by_order_form') {
  157. // Don't use Google Checkout for manual payments either.
  158. unset($form['payments']['new']['method']['#options']['google_checkout']);
  159. }
  160. elseif ($form_id == 'uc_order_view_update_form') {
  161. $form['#submit'][] = 'uc_google_checkout_notify_update';
  162. }
  163. elseif ($form_id == 'uc_store_format_settings_form') {
  164. $form['currency']['uc_currency_code']['#description'] .= ' '. t('Google Checkout only accepts the following currencies: @list', array('@list' => implode(', ', _uc_google_checkout_currency_codes())));
  165. }
  166. }
  167. /**
  168. * Implements hook_nodeapi().
  169. */
  170. function uc_google_checkout_nodeapi(&$node, $op) {
  171. if (uc_product_is_product($node->type)) {
  172. switch ($op) {
  173. case 'insert':
  174. case 'update':
  175. if (isset($node->gc_salable)) {
  176. if (!$node->revision) {
  177. db_query("DELETE FROM {uc_gc_products} WHERE vid = %d", $node->vid);
  178. }
  179. db_query("INSERT INTO {uc_gc_products} (vid, nid, gc_salable) VALUES (%d, %d, %d)",
  180. $node->vid, $node->nid, $node->gc_salable);
  181. }
  182. break;
  183. case 'load':
  184. $salable = db_result(db_query("SELECT gc_salable FROM {uc_gc_products} WHERE vid = %d", $node->vid));
  185. if ($salable === FALSE) {
  186. $salable = TRUE;
  187. }
  188. return array('gc_salable' => $salable);
  189. break;
  190. case 'delete':
  191. db_query("DELETE FROM {uc_gc_products} WHERE nid = %d", $node->nid);
  192. break;
  193. case 'delete revision':
  194. db_query("DELETE FROM {uc_gc_products} WHERE vid = %d", $node->vid);
  195. break;
  196. }
  197. }
  198. }
  199. /******************************************************************************
  200. * Hook Functions (Ubercart) *
  201. ******************************************************************************/
  202. /**
  203. * Implements hook_cart_pane().
  204. */
  205. function uc_google_checkout_cart_pane() {
  206. $panes[] = array(
  207. 'id' => 'uc_google_checkout',
  208. 'title' => t('Google Checkout'),
  209. 'enabled' => TRUE,
  210. 'weight' => 1,
  211. 'body' => '<div align="'. variable_get('uc_google_checkout_button_align', 'right') .'">'. drupal_get_form('uc_google_checkout_cart_form') .'</div>',
  212. );
  213. return $panes;
  214. }
  215. /**
  216. * Implements hook_order_pane().
  217. */
  218. function uc_google_checkout_order_pane() {
  219. $panes[] = array(
  220. 'id' => 'email_allowed',
  221. 'callback' => 'uc_google_checkout_pane_email_allowed',
  222. 'title' => t('Marketing preferences'),
  223. 'desc' => t("Display the customer's preferences about mass-marketing."),
  224. 'class' => 'pos-left',
  225. 'weight' => 4,
  226. 'show' => array('view', 'customer'),
  227. );
  228. return $panes;
  229. }
  230. /**
  231. * Implements hook_line_item().
  232. */
  233. function uc_google_checkout_line_item() {
  234. $items[] = array(
  235. 'id' => 'gc_coupon',
  236. 'title' => t('Google Checkout Coupon'),
  237. 'stored' => TRUE,
  238. 'calculated' => TRUE,
  239. 'weight' => 2,
  240. );
  241. $items[] = array(
  242. 'id' => 'gc_gift_certificate',
  243. 'title' => t('Google Checkout Gift Certificate'),
  244. 'stored' => TRUE,
  245. 'calculated' => TRUE,
  246. 'weight' => 2,
  247. );
  248. return $items;
  249. }
  250. /**
  251. * Implements hook_order().
  252. */
  253. function uc_google_checkout_order($op, &$order, $arg2) {
  254. switch ($op) {
  255. case 'load':
  256. $result = db_query("SELECT * FROM {uc_gc_orders} WHERE order_id = %d", $order->order_id);
  257. if ($gc = db_fetch_object($result)) {
  258. $order->google_order_number = $gc->gc_order_number;
  259. $order->financial_state = $gc->financial_state;
  260. $order->fulfillment_state = $gc->fulfillment_state;
  261. $order->gc_total = $gc->gc_total;
  262. }
  263. break;
  264. case 'can_update':
  265. if (!isset($order->google_order_number) || isset($_SESSION['google_updates']) && $_SESSION['google_updates']) {
  266. return TRUE;
  267. }
  268. switch ($arg2) {
  269. case 'canceled':
  270. if (uc_google_checkout_cancel_order($order)) {
  271. drupal_set_message(t('Cancel order request sent to Google Checkout. The order will be updated momentarily.'));
  272. }
  273. else {
  274. drupal_set_message(t('Order is not canceled in Google Checkout.'));
  275. }
  276. return FALSE;
  277. }
  278. break;
  279. }
  280. }
  281. /**
  282. * Implements hook_payment_method().
  283. */
  284. function uc_google_checkout_payment_method() {
  285. $methods[] = array(
  286. 'id' => 'google_checkout',
  287. 'name' => t('Google Checkout'),
  288. 'title' => t('Google Checkout'),
  289. 'desc' => t('Express payment with Google Checkout.'),
  290. 'callback' => 'uc_payment_method_google_checkout',
  291. 'weight' => 1,
  292. 'checkout' => FALSE,
  293. 'backend' => FALSE,
  294. );
  295. return $methods;
  296. }
  297. /**
  298. * Implements hook_payment_gateway().
  299. */
  300. function uc_google_checkout_payment_gateway() {
  301. $gateways[] = array(
  302. 'id' => 'google_checkout',
  303. 'title' => t('Google Checkout'),
  304. 'description' => t('Express payment with Google Checkout.'),
  305. 'google_checkout' => 'uc_google_checkout_charge',
  306. );
  307. return $gateways;
  308. }
  309. /**
  310. * Implements hook_shipment().
  311. */
  312. function uc_google_checkout_shipment($op, $shipment) {
  313. switch ($op) {
  314. case 'save':
  315. $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
  316. if ($google_order_number && $shipment->is_new) {
  317. $xml_data = '';
  318. foreach ($shipment->packages as $package) {
  319. if ($package->tracking_number) {
  320. $tracking_number = $package->tracking_number;
  321. }
  322. elseif ($shipment->tracking_number) {
  323. $tracking_number = $shipment->tracking_number;
  324. }
  325. if ($tracking_number) {
  326. foreach ($package->products as $product) {
  327. $xml_data .= '<item-shipping-information>';
  328. $xml_data .= '<item-id>';
  329. $xml_data .= '<merchant-item-id>'. check_plain($product->nid .'|'. $product->model) .'</merchant-item-id>';
  330. $xml_data .= '</item-id>';
  331. $xml_data .= '<tracking-data-list>';
  332. $xml_data .= '<tracking-data>';
  333. $xml_data .= '<carrier>'. check_plain($shipment->carrier) .'</carrier>';
  334. $xml_data .= '<tracking-number>'. check_plain($tracking_number) .'</tracking-number>';
  335. $xml_data .= '</tracking-data>';
  336. $xml_data .= '</tracking-data-list>';
  337. $xml_data .= '</item-shipping-information>';
  338. }
  339. }
  340. }
  341. if ($xml_data) {
  342. $request = '<?xml version="1.0" encoding="UTF-8"?>';
  343. $request .= "\n";
  344. $request .= '<ship-items xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
  345. $request .= '<item-shipping-information-list>';
  346. $request .= $xml_data;
  347. $request .= '</item-shipping-information-list>';
  348. $request .= '<send-email>true</send-email>';
  349. $request .= '</ship-items>';
  350. $response = uc_google_checkout_send_request('request', $request);
  351. }
  352. }
  353. break;
  354. case 'delete':
  355. $google_order_number = uc_google_checkout_get_google_number($shipment->order_id);
  356. if ($google_order_number) {
  357. foreach ($shipment->packages as $package) {
  358. foreach ($package->products as $product) {
  359. $reset_ids[] = check_plain($product->nid .'|'. $product->model);
  360. }
  361. }
  362. $request = '<?xml version="1.0" encoding="UTF-8"?>';
  363. $request .= "\n";
  364. $request .= '<reset-items-shipping-information xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
  365. $request .= '<item-ids>';
  366. foreach (array_unique($reset_ids) as $item_id) {
  367. $request .= '<item-id>';
  368. $request .= '<merchant-item-id>'. $item_id .'</merchant-item-id>';
  369. $request .= '</item-id>';
  370. }
  371. $request .= '</item-ids>';
  372. $request .= '<send-email>false</send-email>';
  373. $request .= '</reset-items-shipping-information>';
  374. $response = uc_google_checkout_send_request('request', $request);
  375. }
  376. break;
  377. }
  378. }
  379. /******************************************************************************
  380. * Callback Functions, Forms, and Tables *
  381. ******************************************************************************/
  382. /**
  383. * Form builder for uc_google_checkout_cart_form().
  384. *
  385. * @see uc_google_checkout_cart_form_submit()
  386. * @ingroup forms
  387. */
  388. function uc_google_checkout_cart_form() {
  389. if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
  390. $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
  391. $checkout_url = 'https://checkout.google.com';
  392. }
  393. else {
  394. $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
  395. $checkout_url = 'https://sandbox.google.com/checkout';
  396. }
  397. if (!$merchant_id) {
  398. watchdog('google', 'Google Checkout is enabled, but no Merchant ID found.', array(), WATCHDOG_ERROR, 'admin/store/settings/google_checkout');
  399. return;
  400. }
  401. // Hack to allow the image button to submit.
  402. if (isset($_POST['submit_x'])) {
  403. $form['submit'] = array(
  404. '#type' => 'submit',
  405. '#value' => 'submit',
  406. );
  407. }
  408. global $user;
  409. $id = variable_get('googleanalytics_account', '');
  410. if (module_exists('googleanalytics') && !empty($id) && _googleanalytics_visibility_pages() && _googleanalytics_visibility_user($user)) {
  411. $form['#attributes'] = array('onsubmit' => 'setUrchinInputCode(pageTracker);');
  412. }
  413. $disable = FALSE;
  414. foreach (uc_cart_get_contents() as $item) {
  415. $product = node_load($item->nid);
  416. if (!$product->gc_salable) {
  417. $disable = TRUE;
  418. break;
  419. }
  420. }
  421. switch (variable_get('uc_google_checkout_button_size', 'large')) {
  422. case 'large':
  423. $width = 180;
  424. $height = 46;
  425. break;
  426. case 'medium':
  427. $width = 168;
  428. $height = 44;
  429. break;
  430. case 'small':
  431. $width = 160;
  432. $height = 43;
  433. break;
  434. }
  435. $form['submit_image'] = array(
  436. '#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 .'" />',
  437. );
  438. $form['submit_help'] = array(
  439. '#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>',
  440. );
  441. $form['analyticsdata'] = array(
  442. '#type' => 'hidden',
  443. '#default_value' => '',
  444. );
  445. return $form;
  446. }
  447. /**
  448. * Form submission handler for uc_google_checkout_cart_form().
  449. *
  450. * @see uc_google_checkout_cart_form()
  451. */
  452. function uc_google_checkout_cart_form_submit($form, &$form_state) {
  453. global $user;
  454. $items = uc_cart_get_contents();
  455. if (!is_array($items) || count($items) == 0) {
  456. drupal_set_message(t('You do not have any items in your shopping cart.'));
  457. return;
  458. }
  459. if (empty($_SESSION['cart_order'])) {
  460. $order = uc_order_new($user->uid);
  461. $_SESSION['cart_order'] = $order->order_id;
  462. }
  463. else {
  464. $order = new stdClass();
  465. $order->uid = $user->uid;
  466. $order->order_id = $_SESSION['cart_order'];
  467. $order->primary_email = $user->mail;
  468. $order->order_status = uc_order_state_default('in_checkout');
  469. }
  470. $order->products = $items;
  471. uc_order_save($order);
  472. uc_order_update_status($order->order_id, 'in_google_checkout');
  473. $order->order_status = 'in_google_checkout';
  474. $order->analytics_data = $form_state['values']['analyticsdata'];
  475. $request = uc_google_checkout_cart_request($order);
  476. if ($response = uc_google_checkout_send_request('merchantCheckout', $request)) {
  477. $redirect = (string) $response->{'redirect-url'};
  478. drupal_goto($redirect);
  479. }
  480. }
  481. function uc_google_checkout_cart_request($order) {
  482. if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
  483. $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
  484. }
  485. else {
  486. $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
  487. }
  488. $output = '<?xml version="1.0" encoding="UTF-8"?>';
  489. $output .= "\n";
  490. if (count($order->products)) {
  491. $output .= '<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">';
  492. $output .= '<shopping-cart>';
  493. $output .= '<items>';
  494. foreach ($order->products as $product) {
  495. $output .= '<item>';
  496. $output .= '<item-name>'. check_plain($product->model) .'</item-name>';
  497. $output .= '<item-description>'. check_plain($product->title) .'</item-description>';
  498. $output .= '<unit-price currency="'. variable_get('uc_currency_code', 'USD') .'">'. $product->price .'</unit-price>';
  499. $output .= '<item-weight unit="LB" value="'. $product->weight * uc_weight_conversion($product->weight_units, 'lb') .'" />';
  500. if (!uc_cart_product_is_shippable($product)) {
  501. $output .= '<digital-content>';
  502. $output .= '<display-disposition>PESSIMISTIC</display-disposition>';
  503. $output .= '<email-delivery>true</email-delivery>';
  504. $output .= '</digital-content>';
  505. }
  506. $output .= '<quantity>'. $product->qty .'</quantity>';
  507. $output .= '<merchant-item-id>'. $product->nid .'|'. $product->model .'</merchant-item-id>';
  508. $output .= '</item>';
  509. }
  510. $output .= '</items>';
  511. $output .= '<merchant-private-data>';
  512. $output .= '<cart-id>'. uc_cart_get_id() .'</cart-id>';
  513. $output .= '<order-id>'. $order->order_id .'</order-id>';
  514. $output .= '</merchant-private-data>';
  515. $output .= '</shopping-cart>';
  516. $output .= '<checkout-flow-support>';
  517. $output .= '<merchant-checkout-flow-support>';
  518. if (uc_order_is_shippable($order)) {
  519. $output .= '<shipping-methods>';
  520. $order->delivery_city = variable_get('uc_google_checkout_delivery_city', '');
  521. $order->delivery_zone = variable_get('uc_google_checkout_delivery_zone', 0);
  522. $order->delivery_country = variable_get('uc_google_checkout_delivery_country', 0);
  523. $order->delivery_postal_code = variable_get('uc_google_checkout_delivery_postal_code', '');
  524. $methods = module_invoke_all('shipping_method');
  525. module_load_include('inc', 'uc_quote', 'uc_quote.pages');
  526. $quote_data = _uc_quote_assemble_quotes($order);
  527. foreach ($quote_data as $method_id => $options) {
  528. foreach ($options as $accsrl => $data) {
  529. if (isset($data['rate'])) {
  530. $output .= '<merchant-calculated-shipping name="'. check_plain($methods[$method_id]['quote']['accessorials'][$accsrl]) .'">';
  531. $output .= '<price currency="'. variable_get('uc_currency_code', 'USD') .'">'. $data['rate'] .'</price>';
  532. $output .= '</merchant-calculated-shipping>';
  533. }
  534. }
  535. }
  536. $output .= '</shipping-methods>';
  537. $output .= '<merchant-calculations>';
  538. $output .= '<merchant-calculations-url>'. url('google_checkout/calculations', array('absolute' => TRUE)) .'</merchant-calculations-url>';
  539. $output .= '</merchant-calculations>';
  540. }
  541. $output .= '<analytics-data>'. $order->analytics_data .'</analytics-data>';
  542. $tax_table = '';
  543. $result = db_query("SELECT zone, rate, tax_shipping FROM {uc_gc_taxes}");
  544. while ($tax = db_fetch_object($result)) {
  545. $tax_table .= '<default-tax-rule>';
  546. if ($tax->tax_shipping) {
  547. $tax_table .= '<shipping-taxed>true</shipping-taxed>';
  548. }
  549. $tax_table .= '<rate>'. (float)$tax->rate .'</rate>';
  550. $tax_table .= '<tax-area>';
  551. $tax_table .= '<us-state-area>';
  552. $tax_table .= '<state>'. $tax->zone .'</state>';
  553. $tax_table .= '</us-state-area>';
  554. $tax_table .= '</tax-area>';
  555. $tax_table .= '</default-tax-rule>';
  556. }
  557. if ($tax_table) {
  558. $output .= '<tax-tables>';
  559. $output .= '<default-tax-table>';
  560. $output .= '<tax-rules>';
  561. $output .= $tax_table;
  562. $output .= '</tax-rules>';
  563. $output .= '</default-tax-table>';
  564. $output .= '</tax-tables>';
  565. }
  566. $output .= '<edit-cart-url>'. url('cart', array('absolute' => TRUE)) .'</edit-cart-url>';
  567. if (($page = variable_get('uc_continue_shopping_url', '')) != '<none>') {
  568. $output .= '<continue-shopping-url>'. url($page, array('absolute' => TRUE)) .'</continue-shopping-url>';
  569. }
  570. $output .= '<platform-id>218752253180456</platform-id>';
  571. $output .= '</merchant-checkout-flow-support>';
  572. $output .= '</checkout-flow-support>';
  573. $output .= '</checkout-shopping-cart>';
  574. }
  575. return $output;
  576. }
  577. function uc_google_checkout_headers() {
  578. if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
  579. $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
  580. $merchant_key = variable_get('uc_google_checkout_merchant_key', '');
  581. }
  582. else {
  583. $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
  584. $merchant_key = variable_get('uc_google_checkout_test_merchant_key', '');
  585. }
  586. $headers = array();
  587. $authorization = $merchant_id .':'. $merchant_key;
  588. if ($authorization != ':') {
  589. $headers['Authorization'] = 'Basic '. base64_encode($authorization);
  590. }
  591. $headers['Content-Type'] = 'application/xml; charset=UTF-8';
  592. $headers['Accept'] = 'application/xml; charset=UTF-8';
  593. return $headers;
  594. }
  595. function uc_google_checkout_send_request($api, $request) {
  596. if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
  597. $merchant_id = variable_get('uc_google_checkout_merchant_id', '');
  598. $checkout_url = 'https://checkout.google.com';
  599. }
  600. else {
  601. $merchant_id = variable_get('uc_google_checkout_test_merchant_id', '');
  602. $checkout_url = 'https://sandbox.google.com/checkout';
  603. }
  604. // Google's XML parser doesn't like named entities apparently.
  605. str_replace(array('&amp;', '&lt;', '&gt;'), array('&#x26;', '&#x3c;', '&#x3e;'), $request);
  606. $response_obj = drupal_http_request($checkout_url .'/api/checkout/v2/'. $api .'/Merchant/'. $merchant_id, uc_google_checkout_headers(), 'POST', $request);
  607. if (isset($response_obj->error)) {
  608. watchdog('google', '@error', array('@error' => $response_obj->error), WATCHDOG_ERROR);
  609. }
  610. $response = new SimpleXMLElement($response_obj->data);
  611. if ($response->getName() == 'error') {
  612. $error = (string) $response->{'error-message'};
  613. drupal_set_message($error, 'error');
  614. watchdog('google', '@error', array('@error' => $error), WATCHDOG_ERROR);
  615. return NULL;
  616. }
  617. /**
  618. * Ugly hack to work around PHP bug, details here:
  619. * http://bugs.php.net/bug.php?id=23220
  620. * We strip out errors that look something like:
  621. * warning: fread() [function.fread]: SSL fatal protocol error in...
  622. * Copied from http://drupal.org/node/70915.
  623. */
  624. $messages = drupal_set_message();
  625. $errors = isset($messages['error']) ? $messages['error'] : array();
  626. foreach ($errors as $i => $error) {
  627. if (strpos($error, 'SSL: fatal protocol error in')) {
  628. unset($_SESSION['messages']['error'][$i]);
  629. }
  630. }
  631. if (empty($_SESSION['messages']['error'])) {
  632. unset($_SESSION['messages']['error']);
  633. }
  634. db_query("DELETE FROM {watchdog} WHERE type = 'php' AND variables LIKE '%%SSL: fatal protocol error%%'");
  635. // End of ugly hack.
  636. return $response;
  637. }
  638. function uc_google_checkout_pane_email_allowed($op, $order) {
  639. switch ($op) {
  640. case 'customer':
  641. case 'view':
  642. if (isset($order->data['email_allowed']) && $order->data['email_allowed']) {
  643. $output = t('Customer will accept marketing emails.');
  644. }
  645. else {
  646. $output = t('Customer does not want marketing emails.');
  647. }
  648. return $output;
  649. }
  650. }
  651. /**
  652. * Add setting callbacks to the payment settings section
  653. * The fulfillment sections need coded still. JS.
  654. */
  655. function uc_payment_method_google_checkout($op, &$arg1) {
  656. switch ($op) {
  657. case 'order-view':
  658. $output = l(t('Google Checkout terminal'), 'admin/store/orders/'. $arg1->order_id .'/google_checkout');
  659. return $output;
  660. case 'settings':
  661. $form = array();
  662. $form['link'] = array(
  663. '#value' => l(t('Click here to go to Google Checkout settings.'), 'admin/store/settings/google_checkout'),
  664. );
  665. return $form;
  666. }
  667. }
  668. function uc_google_checkout_new_order($new_order) {
  669. $order_id = $new_order->{'shopping-cart'}->{'merchant-private-data'}->{'order-id'};
  670. $cart_id = (string) $new_order->{'shopping-cart'}->{'merchant-private-data'}->{'cart-id'};
  671. $order = uc_order_load($order_id);
  672. if ($order) {
  673. $shipping_address = $new_order->{'buyer-shipping-address'};
  674. $order->delivery_company = (string) $shipping_address->{'company-name'};
  675. $order->delivery_first_name = (string) $shipping_address->{'structured-name'}->{'first-name'};
  676. $order->delivery_last_name = (string) $shipping_address->{'structured-name'}->{'last-name'};
  677. $order->delivery_phone = (string) $shipping_address->phone;
  678. $order->delivery_street1 = (string) $shipping_address->address1;
  679. $order->delivery_street2 = (string) $shipping_address->address2;
  680. $order->delivery_city = (string) $shipping_address->city;
  681. $zone_id = db_result(db_query("SELECT zone_id FROM {uc_zones} WHERE zone_code = '%s'", $shipping_address->region));
  682. $order->delivery_zone = $zone_id;
  683. $countries = uc_get_country_data(array('country_iso_code_2' => $shipping_address->{'country-code'}));
  684. $order->delivery_country = $countries[0]['country_id'];
  685. $order->delivery_postal_code = (string) $shipping_address->{'postal-code'};
  686. $billing_address = $new_order->{'buyer-billing-address'};
  687. $order->billing_company = (string) $billing_address->{'company-name'};
  688. $order->billing_first_name = (string) $billing_address->{'structured-name'}->{'first-name'};
  689. $order->billing_last_name = (string) $billing_address->{'structured-name'}->{'last-name'};
  690. $order->billing_phone = (string) $billing_address->phone;
  691. $order->billing_street1 = (string) $billing_address->address1;
  692. $order->billing_street2 = (string) $billing_address->address2;
  693. $order->billing_city = (string) $billing_address->city;
  694. if ($billing_address['region'] != $shipping_address->region) {
  695. $zone_id = db_result(db_query("SELECT zone_id FROM {uc_zones} WHERE zone_code = '%s'", $billing_address->region));
  696. }
  697. $order->billing_zone = $zone_id;
  698. if ($billing_address->{'country-code'} != $shipping_address->{'country-code'}) {
  699. $countries = uc_get_country_data(array('country_iso_code_2' => $billing_address->{'country-code'}));
  700. }
  701. $order->billing_country = $countries[0]['country_id'];
  702. $order->billing_postal_code = (string) $billing_address->{'postal-code'};
  703. if (!$order->primary_email) {
  704. $order->primary_email = (string) $billing_address->email;
  705. }
  706. if ($new_order->{'buyer-marketing-preferences'}->{'email-allowed'} == 'true') {
  707. $order->data['email_allowed'] = TRUE;
  708. if (module_exists('simplenews')) {
  709. simplenews_subscribe_user($order->primary_email, variable_get('uc_google_checkout_simplenews_tid', 0), TRUE);
  710. }
  711. }
  712. else {
  713. $order->data['email_allowed'] = FALSE;
  714. if (module_exists('simplenews')) {
  715. simplenews_unsubscribe_user($order->primary_email, variable_get('uc_google_checkout_simplenews_tid', 0), FALSE);
  716. }
  717. }
  718. $order->payment_method = 'google_checkout';
  719. $comments = array();
  720. // Ubercart should already be set up to calculate taxes itself.
  721. //uc_order_line_item_add($order_id, 'tax', t('Total tax'), $new_order->{'order-adjustment'}->{'total-tax'});
  722. if (isset($new_order->{'order-adjustment'}->shipping)) {
  723. $shipping_line = $new_order->{'order-adjustment'}->shipping[0];
  724. if ($shipping_line->{'shipping-cost'}) {
  725. $shipping = array(
  726. 'name' => check_plain($shipping_line->{'shipping-name'}),
  727. 'cost' => $shipping_line->{'shipping-cost'},
  728. );
  729. }
  730. elseif ($shipping_line->{'carrier-calculated-shipping-adjustment'}->{'shipping-cost'}) {
  731. $shipping = array(
  732. 'name' => check_plain($shipping_line->{'carrier-calculated-shipping-adjustment'}->{'shipping-name'}),
  733. 'cost' => $shipping_line->{'carrier-calculated-shipping-adjustment'}->{'shipping-cost'},
  734. );
  735. }
  736. elseif ($shipping_line->{'merchant-calculated-shipping-adjustment'}->{'shipping-cost'}) {
  737. $shipping = array(
  738. 'name' => check_plain($shipping_line->{'merchant-calculated-shipping-adjustment'}->{'shipping-name'}),
  739. 'cost' => $shipping_line->{'merchant-calculated-shipping-adjustment'}->{'shipping-cost'},
  740. );
  741. }
  742. uc_order_line_item_add($order_id, 'shipping', $shipping['name'], $shipping['cost']);
  743. }
  744. if (isset($new_order->{'order-adjustment'}->{'merchant-codes'})) {
  745. foreach ($new_order->{'order-adjustment'}->{'merchant-codes'}->children() as $adjustment) {
  746. $type = $adjustment->getName();
  747. if ($type == 'coupon-adjustment') {
  748. uc_order_line_item_add($order_id, 'gc_coupon', check_plain((string) $adjustment->code), -((string) $adjustment->{'applied-amount'}));
  749. $comments[] = check_plain((string) $adjustment->message);
  750. }
  751. elseif ($type == 'gift-certificate-adjustment') {
  752. uc_order_line_item_add($order_id, 'gc_gift_certificate', check_plain((string) $adjustment->code), -((string) $adjustment->{'applied-amount'}));
  753. $comments[] = check_plain((string) $adjustment->message);
  754. }
  755. }
  756. }
  757. uc_order_save($order);
  758. uc_cart_complete_sale($order);
  759. // uc_cart_complete_sale() empties the current cart (Google Checkout
  760. // API's cart) so we must empty the customer's manually.
  761. uc_cart_empty($cart_id);
  762. // Add a comment to let sales team know this came in through the site.
  763. if (variable_get('uc_google_checkout_mode', 'checkout') == 'checkout') {
  764. $checkout_url = 'https://checkout.google.com';
  765. }
  766. else {
  767. $checkout_url = 'https://sandbox.google.com/checkout';
  768. }
  769. 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');
  770. // uc_cart_complete_sale() also unsets some $_SESSION variables. These
  771. // are tied to the user-id, so we record that for when they log in later.
  772. $users = variable_get('uc_google_checkout_order_users', array());
  773. $users[$order->uid] = $order->uid;
  774. variable_set('uc_google_checkout_order_users', $users);
  775. // Add messages from order adjustments (coupons, gift certificates, etc.).
  776. foreach ($comments as $comment) {
  777. $comment = trim($comment);
  778. if ($comment) {
  779. uc_order_comment_save($order->order_id, 0, $comment, 'order', $order->order_status, 0);
  780. }
  781. }
  782. 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'});
  783. return TRUE;
  784. }
  785. else {
  786. return FALSE;
  787. }
  788. }
  789. function uc_google_checkout_accept_risk($risk) {
  790. $order_id = uc_google_checkout_get_order($risk->{'google-order-number'});
  791. if ($order_id) {
  792. $risk_info = $risk->{'risk-information'};
  793. $assessment = t('Risk information notification:') .'<br />';
  794. $avs_response = $risk_info->{'avs-response'};
  795. switch ($avs_response) {
  796. case 'Y':
  797. $assessment .= t('- Full AVS match (address and postal code)');
  798. break;
  799. case 'P':
  800. $assessment .= t('- Partial AVS match (postal code only)');
  801. break;
  802. case 'A':
  803. $assessment .= t('- Partial AVS match (address only)');
  804. break;
  805. case 'N':
  806. $assessment .= t('- No AVS match');
  807. break;
  808. case 'U':
  809. $assessment .= t('- AVS not supported by issuer');
  810. break;
  811. default:
  812. $assessment .= t('<b>Error:</b> No AVS response.');
  813. break;
  814. }
  815. $assessment .= '<br />';
  816. $cvn_response = $risk_info->{'cvn-response'};
  817. switch ($cvn_response) {
  818. case 'M':
  819. $assessment .= t('- CVN match');
  820. break;
  821. case 'N':
  822. $assessment .= t('- No CVN match');
  823. break;
  824. case 'U':
  825. $assessment .= t('- CVN not available');
  826. break;
  827. case 'E':
  828. $assessment .= t('- CVN error');
  829. break;
  830. default:
  831. $assessment .= t('<b>Error:</b> No CVN response.');
  832. break;
  833. }
  834. $assessment .= '<br />';
  835. $assessment .= t('Partial CC number: %s', array('%s' => $risk_info->{'partial-cc-number'}));
  836. $assessment .= '<br />';
  837. $assessment .= format_plural($risk_info->{'buyer-account-age'}, 'Google Checkout member for @count day.', 'Google Checkout member for @count days.');
  838. $assessment .= '<br />';
  839. $assessment .= t('Eligible for protection: <strong>@bool</strong>', array('@bool' => drupal_strtoupper($risk_info->{'eligible-for-protection'})));
  840. uc_order_comment_save($order_id, 0, $assessment, 'admin', 'chargeable');
  841. return TRUE;
  842. }
  843. else {
  844. return FALSE;
  845. }
  846. }
  847. function uc_google_checkout_order_state_change($change) {
  848. $order_id = uc_google_checkout_get_order($change->{'google-order-number'});
  849. if ($order_id) {
  850. $new_financial = (string) $change->{'new-financial-order-state'};
  851. $new_fulfillment = (string) $change->{'new-fulfillment-order-state'};
  852. $prev_financial = (string) $change->{'previous-financial-order-state'};
  853. $prev_fulfillment = (string) $change->{'previous-fulfillment-order-state'};
  854. 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));
  855. if ($new_financial != $prev_financial) {
  856. $_SESSION['google_updates'] = TRUE;
  857. switch ($new_financial) {
  858. case 'CHARGEABLE':
  859. uc_order_update_status($order_id, 'chargeable');
  860. break;
  861. case 'CHARGING':
  862. watchdog('google', 'Charging @order_id', array('@order_id' => $order_id));
  863. break;
  864. case 'CHARGED':
  865. watchdog('google', 'Charged @order_id', array('@order_id' => $order_id));
  866. break;
  867. case 'PAYMENT_DECLINED':
  868. watchdog('google', 'Payment declined @order_id', array('@order_id' => $order_id));
  869. break;
  870. case 'CANCELLED_BY_GOOGLE':
  871. $message = t('Order %order canceled by Google: %reason', array('%order' => $order_id, '%reason' => $change->reason));
  872. uc_order_comment_save($order_id, 0, $message, 'admin', 'canceled');
  873. case 'CANCELLED':
  874. uc_order_comment_save($order_id, 0, t('Order canceled.'), 'order', 'canceled');
  875. uc_order_update_status($order_id, 'canceled');
  876. break;
  877. default:
  878. break;
  879. }
  880. unset($_SESSION['google_updates']);
  881. }
  882. elseif ($new_fulfillment != $prev_fulfillment) {
  883. $_SESSION['google_updates'] = TRUE;
  884. switch ($new_fulfillment) {
  885. case 'PROCESSING':
  886. watchdog('google', 'Processing @order_id', array('@order_id' => $order_id));
  887. break;
  888. case 'DELIVERED':
  889. uc_order_update_status($order_id, 'completed');
  890. watchdog('google', 'Delivered @order_id', array('@order_id' => $order_id));
  891. break;
  892. case 'WILL_NOT_DELIVER':
  893. watchdog('google', 'Will not deliver @order_id', array('@order_id' => $order_id));
  894. break;
  895. }
  896. unset($_SESSION['google_updates']);
  897. }
  898. return TRUE;
  899. }
  900. else {
  901. return FALSE;
  902. }
  903. }
  904. function uc_google_checkout_authorize_amount($auth) {
  905. global $user;
  906. $order_id = uc_google_checkout_get_order($auth->{'google-order-number'});
  907. if ($order_id) {
  908. $_SESSION['google_updates'] = TRUE;
  909. uc_order_update_status($order_id, 'chargeable');
  910. unset($_SESSION['google_updates']);
  911. $o_comment = t('<b>Authorization:</b> @amount', array('@amount' => uc_currency_format((string) $auth->{'authorization-amount'})));
  912. uc_order_comment_save($order_id, $user->uid, $o_comment);
  913. return TRUE;
  914. }
  915. else {
  916. return FALSE;
  917. }
  918. }
  919. function uc_google_checkout_charge($order_id, $amount) {
  920. $google_order_number = uc_google_checkout_get_google_number($order_id);
  921. $output = '';
  922. $output .= '<?xml version="1.0" encoding="UTF-8"?>';
  923. $output .= "\n";
  924. $output .= '<charge-and-ship-order xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
  925. $output .= '<amount currency="'. variable_get('uc_currency_code', 'USD') .'">'. $amount .'</amount>';
  926. $output .= '</charge-and-ship-order>';
  927. if ($response = uc_google_checkout_send_request('request', $output)) {
  928. if (!uc_google_checkout_charge_order($response)) {
  929. drupal_set_message(t('Charge request sent to Google Checkout. The charge confirmation should appear on this page momentarily.'));
  930. }
  931. }
  932. return 'admin/store/orders/'. $order_id;
  933. }
  934. function uc_google_checkout_charge_order($charge) {
  935. $order_id = uc_google_checkout_get_order($charge->{'google-order-number'});
  936. if ($order_id) {
  937. $amount = (string) $charge->{'latest-charge-amount'};
  938. uc_payment_enter($order_id, 'google_checkout', $amount, 0,
  939. '', t('Payment received by Google Checkout'));
  940. $context = array(
  941. 'revision' => 'formatted-original',
  942. 'type' => 'amount',
  943. );
  944. uc_order_comment_save($order_id, 0, t('Payment of %amount received by Google Checkout.', array('%amount' => uc_price($amount, $context))), 'admin', 'chargeable');
  945. return TRUE;
  946. }
  947. else {
  948. return FALSE;
  949. }
  950. }
  951. function uc_google_checkout_refund($order_id, $amount, $reason, $comment = '') {
  952. $google_order_number = uc_google_checkout_get_google_number($order_id);
  953. $output = '';
  954. $output .= '<?xml version="1.0" encoding="UTF-8"?>';
  955. $output .= "\n";
  956. $output .= '<refund-order xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
  957. $output .= '<amount currency="'. variable_get('uc_currency_code', 'USD') .'">'. $amount .'</amount>';
  958. $output .= '<comment>'. check_plain($comment) .'</comment>';
  959. $output .= '<reason>'. check_plain($reason) .'</reason>';
  960. $output .= '</refund-order>';
  961. if ($response = uc_google_checkout_send_request('request', $output)) {
  962. if (!uc_google_checkout_refund_order($response)) {
  963. drupal_set_message(t('Refund request sent to Google Checkout. The refund confirmation should appear on this page momentarily.'));
  964. }
  965. }
  966. return 'admin/store/orders/'. $order_id;
  967. }
  968. function uc_google_checkout_refund_order($refund) {
  969. $order_id = uc_google_checkout_get_order($refund->{'google-order-number'});
  970. if ($order_id) {
  971. uc_payment_enter($order_id, 'google_checkout', -((string) $refund->{'latest-refund-amount'}),
  972. 0, '', t('Refund received by Google Checkout'));
  973. $context = array(
  974. 'revision' => 'formatted-original',
  975. 'type' => 'amount',
  976. );
  977. 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');
  978. return TRUE;
  979. }
  980. else {
  981. return FALSE;
  982. }
  983. }
  984. function uc_google_checkout_notify_update($form, &$form_state) {
  985. $order = uc_order_load($form_state['values']['order_id']);
  986. if ($order !== FALSE && isset($order->google_order_number) && isset($form_state['values']['order_comment']) && drupal_strlen($form_state['values']['order_comment'])) {
  987. $request = uc_google_checkout_buyer_message_request($form_state['values']['order_id'], $form_state['values']['order_comment']);
  988. $response = uc_google_checkout_send_request('request', $request);
  989. }
  990. }
  991. function uc_google_checkout_buyer_message_request($order_id, $message) {
  992. $google_order_number = uc_google_checkout_get_google_number($order_id);
  993. $output = '<?xml version="1.0" encoding="UTF-8"?>';
  994. $output .= "\n";
  995. $output .= '<send-buyer-message xmlns="http://checkout.google.com/schema/2" google-order-number="'. $google_order_number .'">';
  996. $output .= '<message>'. check_plain($message) .'</message>';
  997. $output .= '<send-email>true</send-email>';
  998. $output .= '</send-buyer-message>';
  999. return $output;
  1000. }
  1001. function uc_google_checkout_cancel_order($order) {
  1002. $request = '<?xml version="1.0" encoding="UTF-8"?>';
  1003. $request .= "\n";
  1004. $request .= '<cancel-order xmlns="http://checkout.google.com/schema/2" google-order-number="'. $order->google_order_number .'">';
  1005. $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>';
  1006. $request .= '</cancel-order>';
  1007. if ($response = uc_google_checkout_send_request('request', $request)) {
  1008. return TRUE;
  1009. }
  1010. else {
  1011. return FALSE;
  1012. }
  1013. }
  1014. function uc_google_checkout_notification_acknowledgement($serial_number) {
  1015. drupal_set_header('HTTP/1.1 200 OK');
  1016. print '<?xml version="1.0" encoding="UTF-8"?>';
  1017. print "\n";
  1018. print '<notification-acknowledgment xmlns="http://checkout.google.com/schema/2" serial-number="'. $serial_number .'" />';
  1019. exit();
  1020. }
  1021. function uc_google_checkout_notification_error($message = NULL) {
  1022. if (is_null($message)) {
  1023. $message = t('Unknown order id or malformed XML.');
  1024. }
  1025. drupal_set_header('HTTP/1.1 400 Bad Request');
  1026. watchdog('google', '!message', array('!message' => $message), WATCHDOG_ERROR);
  1027. exit();
  1028. }
  1029. function uc_google_checkout_get_order($google_order_number) {
  1030. return db_result(db_query("SELECT order_id FROM {uc_gc_orders} WHERE gc_order_number = '%s'", $google_order_number));
  1031. }
  1032. function uc_google_checkout_get_google_number($order_id) {
  1033. return db_result(db_query("SELECT gc_order_number FROM {uc_gc_orders} WHERE order_id = %d", $order_id));
  1034. }
  1035. function uc_google_checkout_shipping_services() {
  1036. return array_merge(uc_google_checkout_fedex_services(), uc_google_checkout_ups_services(), uc_google_checkout_usps_services());
  1037. }
  1038. function uc_google_checkout_fedex_services() {
  1039. return array(
  1040. 'fedex_ground' => 'Ground',
  1041. 'fedex_home' => 'Home Delivery',
  1042. 'fedex_express' => 'Express Saver',
  1043. 'fedex_first' => 'First Overnight',
  1044. 'fedex_priority' => 'Priority Overnight',
  1045. 'fedex_standard' => 'Standard Overnight',
  1046. 'fedex_2day' => '2Day',
  1047. );
  1048. }
  1049. function uc_google_checkout_ups_services() {
  1050. return array(
  1051. 'ups_next_day' => 'Next Day Air',
  1052. 'ups_next_day_am' => 'Next Day Air Early AM',
  1053. 'ups_next_day_saver' => 'Next Day Air Saver',
  1054. 'ups_2nd_day' => '2nd Day Air',
  1055. 'ups_2nd_day_am' => '2nd Day Air AM',
  1056. 'ups_3_day' => '3 Day Select',
  1057. 'ups_ground' => 'Ground',
  1058. );
  1059. }
  1060. function uc_google_checkout_usps_services() {
  1061. return array(
  1062. 'usps_express' => 'Express Mail',
  1063. 'usps_priority' => 'Priority Mail',
  1064. 'usps_parcel' => 'Parcel Post',
  1065. 'usps_media' => 'Media Mail',
  1066. );
  1067. }
  1068. function uc_google_checkout_shipping_companies() {
  1069. return array(
  1070. 'fedex' => 'FedEx',
  1071. 'ups' => 'UPS',
  1072. 'usps' => 'USPS',
  1073. );
  1074. }
  1075. /**
  1076. * Returns an array of options for the currency selection widget.
  1077. */
  1078. function _uc_google_checkout_currency_codes() {
  1079. return drupal_map_assoc(array('AUD', 'CAD', 'EUR', 'GBP', 'HKD', 'JPY', 'USD'));
  1080. }
  1081. function uc_google_checkout_avs_code($code = NULL) {
  1082. $codes = array(
  1083. 'Y' => t('Full AVS match (address and postal code)'),
  1084. 'P' => t('Partial AVS match (postal code only)'),
  1085. 'A' => t('Partial AVS match (address only)'),
  1086. 'N' => t('No AVS match'),
  1087. 'U' => t('AVS not supported by issuer'),
  1088. );
  1089. if ($code) {
  1090. return isset($codes[$code]) ? $codes[$code] : '';
  1091. }
  1092. else {
  1093. return $codes;
  1094. }
  1095. }
  1096. function uc_google_checkout_cvn_code($code = NULL) {
  1097. $codes = array(
  1098. 'M' => t('CVN match'),
  1099. 'N' => t('No CVN match'),
  1100. 'U' => t('CVN not available'),
  1101. 'E' => t('CVN error'),
  1102. );
  1103. if ($code) {
  1104. return isset($codes[$code]) ? $codes[$code] : '';
  1105. }
  1106. else {
  1107. return $codes;
  1108. }
  1109. }