views:

659

answers:

2

I am planning to integrate a Google Checkout payment system on a social networking website. The idea is that members can buy "tokens" for real money (which are sort of the website currency) and then they can buy access to some extra content on the website etc.

What I want to do is create a Google Checkout button that takes a member to the checkout page where he pays with his credit or debit card. What I want is the Google Checkout to notify notify my server whether the purchase of tokens was successful (if the credit/debit card was charged) so I can update the local database.

The website is coded in PHP/MySQL.

I have downloaded the sample PHP code from here: code.google.com/p/google-checkout-php-sample-code/wiki/Documentation

I know how to create a Google checkout button and I have also placed the responsehandlerdemo.php file on my server. This is the file the Google Checkout is supposed to send response to (of course I set the path to the file in Google merchant account).

Now in the response handler file there is a switch block with several case statements. Which one means that the payment was successful and I can add tokens to the member account in the local database?

  switch ($root) {
case "request-received": {
  break;
}
case "error": {
  break;
}
case "diagnosis": {
  break;
}
case "checkout-redirect": {
  break;
}
case "merchant-calculation-callback": {
  // Create the results and send it
  $merchant_calc = new GoogleMerchantCalculations($currency);

  // Loop through the list of address ids from the callback
  $addresses = get_arr_result($data[$root]['calculate']['addresses']['anonymous-address']);
  foreach($addresses as $curr_address) {
    $curr_id = $curr_address['id'];
    $country = $curr_address['country-code']['VALUE'];
    $city = $curr_address['city']['VALUE'];
    $region = $curr_address['region']['VALUE'];
    $postal_code = $curr_address['postal-code']['VALUE'];

    // Loop through each shipping method if merchant-calculated shipping
    // support is to be provided
    if(isset($data[$root]['calculate']['shipping'])) {
      $shipping = get_arr_result($data[$root]['calculate']['shipping']['method']);
      foreach($shipping as $curr_ship) {
        $name = $curr_ship['name'];
        //Compute the price for this shipping method and address id
        $price = 12; // Modify this to get the actual price
        $shippable = "true"; // Modify this as required
        $merchant_result = new GoogleResult($curr_id);
        $merchant_result->SetShippingDetails($name, $price, $shippable);

        if($data[$root]['calculate']['tax']['VALUE'] == "true") {
          //Compute tax for this address id and shipping type
          $amount = 15; // Modify this to the actual tax value
          $merchant_result->SetTaxDetails($amount);
        }

        if(isset($data[$root]['calculate']['merchant-code-strings']
            ['merchant-code-string'])) {
          $codes = get_arr_result($data[$root]['calculate']['merchant-code-strings']
              ['merchant-code-string']);
          foreach($codes as $curr_code) {
            //Update this data as required to set whether the coupon is valid, the code and the amount
            $coupons = new GoogleCoupons("true", $curr_code['code'], 5, "test2");
            $merchant_result->AddCoupons($coupons);
          }
         }
         $merchant_calc->AddResult($merchant_result);
      }
    } else {
      $merchant_result = new GoogleResult($curr_id);
      if($data[$root]['calculate']['tax']['VALUE'] == "true") {
        //Compute tax for this address id and shipping type
        $amount = 15; // Modify this to the actual tax value
        $merchant_result->SetTaxDetails($amount);
      }
      $codes = get_arr_result($data[$root]['calculate']['merchant-code-strings']
          ['merchant-code-string']);
      foreach($codes as $curr_code) {
        //Update this data as required to set whether the coupon is valid, the code and the amount
        $coupons = new GoogleCoupons("true", $curr_code['code'], 5, "test2");
        $merchant_result->AddCoupons($coupons);
      }
      $merchant_calc->AddResult($merchant_result);
    }
  }
  $Gresponse->ProcessMerchantCalculations($merchant_calc);
  break;
}
case "new-order-notification": {
  $Gresponse->SendAck();
  break;
}
case "order-state-change-notification": {
  $Gresponse->SendAck();
  $new_financial_state = $data[$root]['new-financial-order-state']['VALUE'];
  $new_fulfillment_order = $data[$root]['new-fulfillment-order-state']['VALUE'];

  switch($new_financial_state) {
    case 'REVIEWING': {
      break;
    }
    case 'CHARGEABLE': {
      //$Grequest->SendProcessOrder($data[$root]['google-order-number']['VALUE']);
      //$Grequest->SendChargeOrder($data[$root]['google-order-number']['VALUE'],'');
      break;
    }
    case 'CHARGING': {
      break;
    }
    case 'CHARGED': {
      break;
    }
    case 'PAYMENT_DECLINED': {
      break;
    }
    case 'CANCELLED': {
      break;
    }
    case 'CANCELLED_BY_GOOGLE': {
      //$Grequest->SendBuyerMessage($data[$root]['google-order-number']['VALUE'],
      //    "Sorry, your order is cancelled by Google", true);
      break;
    }
    default:
      break;
  }

  switch($new_fulfillment_order) {
    case 'NEW': {
      break;
    }
    case 'PROCESSING': {
      break;
    }
    case 'DELIVERED': {
      break;
    }
    case 'WILL_NOT_DELIVER': {
      break;
    }
    default:
      break;
  }
  break;
}
case "charge-amount-notification": {
  //$Grequest->SendDeliverOrder($data[$root]['google-order-number']['VALUE'],
  //    <carrier>, <tracking-number>, <send-email>);
  //$Grequest->SendArchiveOrder($data[$root]['google-order-number']['VALUE'] );
  $Gresponse->SendAck();
  break;
}
case "chargeback-amount-notification": {
  $Gresponse->SendAck();
  break;
}
case "refund-amount-notification": {
  $Gresponse->SendAck();
  break;
}
case "risk-information-notification": {
  $Gresponse->SendAck();
  break;
}
default:
  $Gresponse->SendBadRequestStatus("Invalid or not supported Message");
  break;

}

I guess that case 'CHARGED' is the one, am I right?

Second question, do I need an SSL certificate to receive response from Google Checkout? According to this I do: groups.google.com/group/google-checkout-api-php/browse_thread/thread/10ce55177281c2b0

But I don's see it mentioned anywhere in the official documentation.

Thank you.

+4  A: 

I integrated this into my site over 6 months ago. It's very low volume, but works good so far.


The first thing that you should worry about is 'CHARGEABLE'. This means that the credit card has been approved for the transaction, but it will not actually charge the funds until you take action. In order to send the charge request, simply un-comment the two lines under CHARGEABLE. You can change your settings to make it automatically charge the card in 'settings' > 'preferences', but you might as well just un-comment the 2 lines and leave your options open.

Note that you might want to WAIT for the 'risk-information-notification' and determine if the risk check passed before approving the charge ($data[$root]['risk-information']['eligible-for-protection']['VALUE']). Although, seems you are talking about digital goods the possibility of chargebacks might not matter to you.

At some point, I'm sure you should also check that the request has sufficient information for you to link the funds to some account before you charge it, but maybe this is just my paranoia.


The other state that I use is 'charge-amount-notification'. It's completely possible that there is a way to use 'CHARGED', but I don't that 'CHARGED' provides an amount that was actually charged. ($amount_charged = $data[$root]['total-charge-amount']['VALUE'];)


As for the SSL, if you check the location where you enter the callback URL it states the following: "Specify a URL for Google to notify you of new orders and changes in order state. You must provide the URL of a server running 128-bit SSLv3 or TLS"


Answer to your comment: I do this under 'new_order_notification', not sure if you can do it elsewhere.

$items = get_arr_result( $data[$root]['shopping-cart']['items']['item'] ); 
foreach( $items as $item ) { 
   if( !isset ( $item['merchant-item-id']['VALUE'] ) ) { 
     //error 
     return; 
   } 
   $request_item_id = $item['merchant-item-id']['VALUE']; 
   //save your item id with corresponding google order id for further processing
}
therealsix
Thank you, one more thing. How can I access the merchant item id (the id I manually set for an item with $item->SetMerchantItemId($id) method). Will this work? $order_id = $data[$root]['merchant-item-id']['VALUE'];
Richard Knop
I need that to know which row in my local database to update.
Richard Knop
Answer added to 'Answer' :)
therealsix
Thanks again, this was very helpful :) One more question if I may. Is Hostgator shared SSL good enough for the responsehandler.php file? Or do I have to buy a private one? Also, the responsehandler.php is the only file that need to be secured with SSL, I don't need to use SSL on other pages (shopping cart on my website etc).
Richard Knop
Because it seems my responsehandler.php is not working. Any code I put there does not get executed.
Richard Knop
Assuming it meets the 128-bit SSL v3 or TLS requirement, there is no way that I know of for them to tell that it is shared. I believe it should work without SSL on the sandbox also. What do you get when you go to your responsehandler URL?
therealsix
A: 

Am having the same problem. The logs show up perfectly, but any code I put in the various states of the order, doesn't get executed at all.

Edy