/** * Constructor. * Set up the pp_data array. */ function __construct($A = array()) { $this->gw_id = 'amazon'; parent::__construct($A); list($ccode, $amount) = preg_split('/\\ +/', $A['transactionAmount']); $this->pp_data['txn_id'] = $A['transactionId']; $this->pp_data['payer_email'] = $A['buyerEmail']; $this->pp_data['payer_name'] = $A['buyerName']; $this->pp_data['pmt_date'] = strftime('%d %b %Y %H:%M:%S', $A['transactionDate']); $this->pp_data['pmt_gross'] = (double) $amount; $this->pp_data['gw_name'] = $this->gw->Description(); $this->pp_data['pmt_status'] = $A['status']; // Check a couple of vars to see if a shipping address was supplied if (isset($A['addressLine1']) || isset($A['city'])) { $this->pp_data['shipto'] = array('name' => $A['addressName'], 'address1' => $A['addressLine1'], 'address2' => $A['addressLine2'], 'city' => $A['city'], 'state' => $A['state'], 'country' => $A['country'], 'zip' => $A['zip'], 'phone' => $A['phoneNumber']); } $custom = explode(';', $A['referenceId']); foreach ($custom as $name => $temp) { list($name, $value) = explode(':', $temp); $this->pp_data['custom'][$name] = $value; } if ($this->pp_data['custom']['transtype'] == 'cart') { USES_paypal_class_cart(); $cart = new ppCart($this->pp_data['custom']['cart_id']); foreach ($cart->Cart() as $itm_id => $data) { $this->AddItem($itm_id, $data['quantity'], $data['price']); } } else { $items = explode('::', $A['paymentReason']); foreach ($items as $item) { list($itm_id, $price, $qty) = explode(';', $item); $this->AddItem($itm_id, $qty, $price); } } }
/** * Process an incoming IPN transaction * Do the following: * 1. Verify IPN * 2. Log IPN * 3. Check that transaction is complete * 4. Check that transaction is unique * 5. Check for valid receiver email address * 6. Process IPN * * @uses BaseIPN::AddItem() * @uses BaseIPN::handleFailure() * @uses BaseIPN::handlePurchase() * @uses BaseIPN::isUniqueTxnId() * @uses BaseIPN::isSufficientFunds() * @uses BaseIPN::Log() * @uses Verify() * @uses isStatusCompleted() * @param array $in POST variables of transaction * @return boolean true if processing valid and completed, false otherwise */ public function Process() { // If no data has been received, then there's nothing to do. if (empty($this->ipn_data)) { return false; } if (!$this->Verify()) { $logId = $this->Log(false); $this->handleFailure(PAYPAL_FAILURE_VERIFY, "({$logId}) Verification failed"); return false; } else { $logId = $this->Log(true); } // Set the custom data field to the exploded value. This has to // be done after Verify() or the Paypal verification will fail. $this->pp_data['custom'] = $this->custom; switch ($this->ipn_data['txn_type']) { case 'web_accept': //usually buy now //usually buy now case 'send_money': //usually donation/send money // Process Buy Now & Send Money $fees_paid = $this->ipn_data['tax'] + $this->pp_data['pmt_shipping'] + $this->pp_data['pmt_handling']; if (!empty($this->ipn_data['item_number'])) { if (!isset($this->ipn_data['quantity']) || (double) $this->ipn_data['quantity'] == 0) { $this->ipn_data['quantity'] = 1; } $payment_gross = $this->pp_data['pmt_gross'] - $fees_paid; $unit_price = $payment_gross / $this->ipn_data['quantity']; $this->AddItem($this->ipn_data['item_number'], $this->ipn_data['quantity'], $unit_price, $this->ipn_data['item_name'], $this->pp_data['pmt_shipping'], $this->pp_data['pmt_handling']); $currency = $this->pp_data['currency']; PAYPAL_debug("Net Settled: {$payment_gross} {$currency}"); if ($this->isSufficientFunds()) { $this->handlePurchase(); } else { $this->handleFailure(PAYPAL_FAILURE_FUNDS, "({$logId}) Insufficient funds for purchase"); return false; } } break; case 'cart': // shopping cart $fees_paid = $this->pp_data['pmt_tax'] + $this->pp_data['pmt_shipping'] + $this->pp_data['pmt_handling']; USES_paypal_class_cart(); if (empty($this->pp_data['custom']['cart_id'])) { $this->handleFailure(NULL, 'Missing Cart ID'); return false; } // Create a cart and read the info from the cart table. // Actual items purchased and prices will come from the IPN. $ppCart = new ppCart($this->pp_data['custom']['cart_id']); $Cart = $ppCart->Cart(); $items = array(); for ($i = 1; $i <= $this->ipn_data['num_cart_items']; $i++) { // PayPal returns the total price as mc_gross_X, so divide // by the quantity to get back to a unit price. if (!isset($this->ipn_data["quantity{$i}"]) || (double) $this->ipn_data["quantity{$i}"] == 0) { $this->ipn_data["quantity{$i}"] = 1; } $item_gross = $this->ipn_data["mc_gross_{$i}"]; if (isset($this->ipn_data["mc_shipping{$i}"])) { $item_shipping = (double) $this->ipn_data["mc_shipping{$i}"]; $item_gross -= $item_shipping; } else { $item_shipping = 0; } if (isset($this->ipn_data["tax{$i}"])) { $item_tax = (double) $this->ipn_data["tax{$i}"]; $item_gross -= $item_tax; } else { $item_tax = 0; } if (isset($this->ipn_data["mc_handling{$i}"])) { $item_handling = (double) $this->ipn_data["mc_handling{$i}"]; $item_gross -= $item_handling; } else { $item_handling = 0; } $unit_price = $item_gross / (double) $this->ipn_data["quantity{$i}"]; // Add the item to the array for the order creation. // IPN item numbers are indexes into the cart, so get the // actual product ID from the cart $this->AddItem($Cart[$this->ipn_data["item_number{$i}"]]['item_id'], $this->ipn_data["quantity{$i}"], $unit_price, $this->ipn_data["item_name{$i}"], $item_shipping, $item_handling, $item_tax, $Cart[$this->ipn_data["item_number{$i}"]]['extras']); } $payment_gross = $this->ipn_data['mc_gross'] - $fees_paid; PAYPAL_debug("Received {$payment_gross} gross payment"); //$currency = $this->ipn_data['mc_currency']; if ($this->isSufficientFunds()) { $this->handlePurchase(); } else { $this->handleFailure(PAYPAL_FAILURE_FUNDS, "({$logId}) Insufficient/incorrect funds for purchase"); return false; } break; // other, unknown, unsupported // other, unknown, unsupported default: switch ($this->ipn_data['reason_code']) { case 'refund': $this->handleRefund(); break; default: $this->handleFailure(PAYPAL_FAILURE_UNKNOWN, "({$logId}) Unknown transaction type"); return false; break; } break; } return true; }
/** * Processes the purchase, for purchases made without an IPN message. * * @param array $vals Submitted values, e.g. $_POST */ public function handlePurchase($vals = array()) { global $_TABLES, $_CONF, $_PP_CONF; USES_paypal_functions(); USES_paypal_class_cart(); USES_paypal_class_order(); USES_paypal_class_product(); if (!empty($vals['cart_id'])) { $cart = new ppCart($vals['cart_id']); if (!$cart->hasItems()) { return; } // shouldn't be empty $items = $cart->Cart(); } else { $cart = new ppCart(); } // Create an order record to get the order ID $Order = $this->CreateOrder($vals, $cart); $db_order_id = DB_escapeString($Order->order_id); $prod_types = 0; // For each item purchased, record purchase in purchase table foreach ($items as $id => $item) { //COM_errorLog("Processing item: $id"); list($item_number, $item_opts) = PAYPAL_explode_opts($id, true); // If the item number is numeric, assume it's an // inventory item. Otherwise, it should be a plugin-supplied // item with the item number like pi_name:item_number:options if (PAYPAL_is_plugin_item($item_number)) { PAYPAL_debug("handlePurchase for Plugin item " . $item_number); // Initialize item info array to be used later $A = array(); // Split the item number into component parts. It could // be just a single string, depending on the plugin's needs. $pi_info = explode(':', $item['item_number']); PAYPAL_debug('Paymentgw::handlePurchase() pi_info: ' . print_r($pi_info, true)); $status = LGLIB_invokeService($pi_info[0], 'productinfo', array($item_number, $item_opts), $product_info, $svc_msg); if ($status != PLG_RET_OK) { $product_info = array(); } if (!empty($product_info)) { $items[$id]['name'] = $product_info['name']; } PAYPAL_debug("Paymentgw::handlePurchase() Got name " . $items[$id]['name']); $vars = array('item' => $item, 'ipn_data' => array()); $status = LGLIB_invokeService($pi_info[0], 'handlePurchase', $vars, $A, $svc_msg); if ($status != PLG_RET_OK) { $A = array(); } // Mark what type of product this is $prod_types |= PP_PROD_VIRTUAL; } else { PAYPAL_debug("Paypal item " . $item_number); $P = new Product($item_number); $A = array('name' => $P->name, 'short_description' => $P->short_description, 'expiration' => $P->expiration, 'prod_type' => $P->prod_type, 'file' => $P->file, 'price' => $item['price']); if (!empty($item_opts)) { $opts = explode(',', $itemopts); $opt_str = $P->getOptionDesc($opts); if (!empty($opt_str)) { $A['short_description'] .= " ({$opt_str})"; } $item_number .= '|' . $item_opts; } // Mark what type of product this is $prod_types |= $P->prod_type; } // An invalid item number, or nothing returned for a plugin if (empty($A)) { //$this->Error("Item {$item['item_number']} not found"); continue; } // If it's a downloadable item, then get the full path to the file. // TODO: pp_data isn't available here, should be from $vals? if (!empty($A['file'])) { $this->items[$id]['file'] = $_PP_CONF['download_path'] . $A['file']; $token_base = $this->pp_data['txn_id'] . time() . rand(0, 99); $token = md5($token_base); $this->items[$id]['token'] = $token; } else { $token = ''; } $items[$id]['prod_type'] = $A['prod_type']; // If a custom name was supplied by the gateway's IPN processor, // then use that. Otherwise, plug in the name from inventory or // the plugin, for the notification email. if (empty($item['name'])) { $items[$id]['name'] = $A['short_description']; } // Add the purchase to the paypal purchase table $uid = isset($vals['uid']) ? (int) $vals['uid'] : $_USER['uid']; $sql = "INSERT INTO {$_TABLES['paypal.purchases']} SET \n order_id = '{$db_order_id}',\n product_id = '{$item_number}',\n description = '{$items[$id]['name']}',\n quantity = '{$item['quantity']}', \n user_id = '{$uid}', \n txn_type = '{$this->gw_id}',\n txn_id = '', \n purchase_date = '{$_PP_CONF['now']->toMySQL()}', \n status = 'complete',\n token = '{$token}',\n price = " . (double) $item['price'] . ",\n options = '" . DB_escapeString($item_opts) . "'"; // add an expiration date if appropriate if (is_numeric($A['expiration']) && $A['expiration'] > 0) { $sql .= ", expiration = DATE_ADD('{$_PP_CONF['now']->toMySQL()}', INTERVAL {$A['expiration']} DAY)"; } //echo $sql;die; PAYPAL_debug($sql); DB_query($sql); } // foreach item // If this was a user's cart, then clear that also if (isset($vals['cart_id']) && !empty($vals['cart_id'])) { DB_delete($_TABLES['paypal.cart'], 'cart_id', $vals['cart_id']); } }