/** * Add the event fee to the shopping cart * No checking is done here to see if it's paid, that must be done * by the caller. * * @param boolean $info True to just return vars, False to add to cart * @return array Array of cart vars */ public function AddToCart($tick_type, $qty = 1) { global $LANG_EVLIST, $_CONF; USES_evlist_class_tickettype(); $TickType = new evTicketType($tick_type); $fee = $this->Event->options['tickets'][$tick_type]['fee']; $rp_id = $TickType->event_pass ? 0 : $this->rp_id; $evCart = array('item_number' => 'evlist:eventfee:' . $this->Event->id . '/' . $tick_type . '/' . $rp_id, 'item_name' => $TickType->description . ': ' . $LANG_EVLIST['event_fee'] . ' - ' . $this->Event->Detail->title . ' ' . $this->start_date1 . ' ' . $this->start_time1, 'short_description' => $TickType->description . ': ' . $this->Event->Detail->title . ' ' . $this->start_date1 . ' ' . $this->start_time1, 'amount' => sprintf("%5.2f", (double) $fee), 'quantity' => $qty, 'extras' => array('shipping' => 0)); LGLIB_invokeService('paypal', 'addCartItem', $evCart, $output, $msg); return $evCart; }
/** * Diaplay the product catalog items. * * @return string HTML for product catalog. */ function PAYPAL_ProductList($cat = 0, $search = '') { global $_TABLES, $_CONF, $_PP_CONF, $LANG_PP, $_USER, $_PLUGINS, $_IMAGE_TYPE, $_GROUPS; USES_paypal_class_product(); if (SEC_hasRights('paypal.admin')) { $isAdmin = true; } else { $isAdmin = false; } $my_groups = implode(',', $_GROUPS); $cat_name = ''; $breadcrumbs = ''; $img_url = ''; $display = ''; if ($cat != 0) { $breadcrumbs = PAYPAL_Breadcrumbs($cat); $cat = (int) $cat; $A = DB_fetchArray(DB_query("SELECT cat_name, image\n FROM {$_TABLES['paypal.categories']}\n WHERE cat_id='{$cat}' " . COM_getPermSQL('AND')), false); if (!empty($A)) { $cat_name = $A['cat_name']; if (!empty($A['image']) && is_file($_CONF['path_html'] . $_PP_CONF['pi_name'] . '/images/categories/' . $A['image'])) { $img_url = PAYPAL_URL . '/images/categories/' . $A['image']; } } } // Display categories if (isset($_PP_CONF['cat_columns']) && $_PP_CONF['cat_columns'] > 0) { $sql = "SELECT cat.cat_id, cat.cat_name, count(prod.id) AS cnt \n FROM {$_TABLES['paypal.categories']} cat\n LEFT JOIN {$_TABLES['paypal.products']} prod\n ON prod.cat_id = cat.cat_id\n WHERE cat.enabled = '1' AND cat.parent_id = '{$cat}' \n AND prod.enabled = '1' " . COM_getPermSQL('AND', 0, 2, 'cat') . " GROUP BY cat.cat_id\n ORDER BY cat.cat_name"; //HAVING cnt > 0 //echo $sql;die; $CT = new Template(PAYPAL_PI_PATH . '/templates'); $CT->set_file(array('table' => 'category_table.thtml', 'row' => 'category_row.thtml', 'category' => 'category.thtml')); $CT->set_var('width', floor(100 / $_PP_CONF['cat_columns'])); if ($breadcrumbs != '') { $CT->set_var('breadcrumbs', $breadcrumbs); } if ($img_url != '') { $CT->set_var('catimg_url', $img_url); } $res = DB_query($sql); $A = array(); while ($C = DB_fetchArray($res, false)) { $A[$C['cat_id']] = array($C['cat_name'], $C['cnt']); } // Now get categories from plugins foreach ($_PLUGINS as $pi_name) { $function = 'USES_' . $pi_name . '_paypal'; if (function_exists($function)) { $function(); $function = 'plugin_paypal_getcategories_' . $pi_name; if (function_exists($function)) { $pi_cats = $function(); foreach ($pi_cats as $catid => $data) { $A[$catid] = $data; } } } } $i = 1; $nrows = count($A); foreach ($A as $category => $info) { $CT->set_var(array('category_name' => $info[0], 'category_link' => PAYPAL_URL . '/index.php?category=' . urlencode($category))); /*if ($category == $cat) { $CT->set_var('curr', 'current'); $cat_name = $info[0]; } else { $CT->set_var('curr', 'other'); }*/ $CT->parse('catrow', 'category', true); if ($i % $_PP_CONF['cat_columns'] == 0) { $CT->parse('categories', 'row', true); $CT->set_var('catrow', ''); } $i++; } if ($nrows % $_PP_CONF['cat_columns'] != 0) { $CT->parse('categories', 'row', true); } $display .= $CT->parse('', 'table'); } /*$sortby_opts = array( 'name' => $LANG_PP['name'], 'price' => $LANG_PP['price'], 'dt_add' => $LANG_PP['dt_add'], ); switch ($_REQUEST['sortby']){ case 'name': case 'price': case 'dt_add': $sortby = $_REQUEST['sortby']; break; default: $sortby = $_PP_CONF['order']; break; } $sortby_options = ''; foreach ($sortby_opts as $value=>$text) { $sel = $value == $sortby ? ' selected="selected"' : ''; $sortby_options .= "<option value=\"$value\" $sel>$text</option>\n"; } $sortdir = $_REQUEST['sortdir'] == 'DESC' ? 'DESC' : 'ASC';*/ $sortby = $_PP_CONF['order']; $sortdir = 'ASC'; // Get products from database. "c.enabled is null" is to allow products // with no category defined $sql = " FROM {$_TABLES['paypal.products']} p\n LEFT JOIN {$_TABLES['paypal.categories']} c\n ON p.cat_id = c.cat_id\n WHERE p.enabled=1 \n AND (\n (c.enabled=1 " . COM_getPermSQL('AND', 0, 2, 'c') . ")\n OR c.enabled IS NULL\n )\n AND (\n p.track_onhand = 0 OR p.onhand > 0 OR p.oversell < 2\n )"; $pagenav_args = array(); // If applicable, limit by category if (!empty($_REQUEST['category'])) { $cat_list = $_REQUEST['category']; $cat_list .= PAYPAL_recurseCats('PAYPAL_callbackCatCommaList', 0, $_REQUEST['category']); if (!empty($cat_list)) { $sql .= " AND c.cat_id IN ({$cat_list})"; } $pagenav_args[] = 'category=' . urlencode($_REQUEST['category']); } else { $cat_list = ''; } // If applicable, limit by search string if (!empty($_REQUEST['search_name'])) { $srch = DB_escapeString($_REQUEST['search_name']); $sql .= " AND (p.name like '%{$srch}%' OR \n p.short_description like '%{$srch}%' OR\n p.description like '%{$srch}%' OR\n p.keywords like '%{$srch}%')"; //if (!$isAdmin) $sql .= " AND p.grp_access IN ($my_groups) "; $pagenav_args[] = 'search_name=' . urlencode($_REQUEST['search_name']); } // If applicable, order by $sql .= " ORDER BY {$sortby} {$sortdir}"; // If applicable, handle pagination of query if (isset($_PP_CONF['prod_per_page']) && $_PP_CONF['prod_per_page'] > 0) { // Count products from database $res = DB_query('SELECT COUNT(*) as cnt ' . $sql); $x = DB_fetchArray($res, false); if (isset($x['cnt'])) { $count = (int) $x['cnt']; } else { $count = 0; } // Make sure page requested is reasonable, if not, fix it if (!isset($_REQUEST['page']) || $_REQUEST['page'] <= 0) { $_REQUEST['page'] = 1; } $page = (int) $_REQUEST['page']; $start_limit = ($page - 1) * $_PP_CONF['prod_per_page']; if ($start_limit > $count) { $page = ceil($count / $_PP_CONF['prod_per_page']); } // Add limit for pagination (if applicable) if ($count > $_PP_CONF['prod_per_page']) { $sql .= " LIMIT {$start_limit}, {$_PP_CONF['prod_per_page']}"; } } // Re-execute query with the limit clause in place $res = DB_query('SELECT DISTINCT p.id ' . $sql); // Create product template $product = new Template(PAYPAL_PI_PATH . '/templates'); $product->set_file(array('start' => 'product_list_start.thtml', 'end' => 'product_list_end.thtml', 'product' => 'product_list_item.thtml', 'download' => 'buttons/btn_download.thtml', 'login_req' => 'buttons/btn_login_req.thtml', 'btn_details' => 'buttons/btn_details.thtml')); if ($nrows == 0 && COM_isAnonUser()) { $product->set_var('anon_and_empty', 'true'); } $product->set_var(array('pi_url' => PAYPAL_URL, 'user_id' => $_USER['uid'], 'currency' => $_PP_CONF['currency'])); if (!empty($cat_name)) { $product->set_var('title', $cat_name); } else { $product->set_var('title', $LANG_PP['blocktitle']); } /*$product->set_var('sortby_options', $sortby_options); if ($sortdir == 'DESC') { $product->set_var('sortdir_desc_sel', ' selected="selected"'); } else { $product->set_var('sortdir_asc_sel', ' selected="selected"'); } $product->set_var('sortby', $sortby); $product->set_var('sortdir', $sortdir);*/ $display .= $product->parse('', 'start'); // Create an empty product object $P = new Product(); if ($_PP_CONF['ena_ratings'] == 1) { $PP_ratedIds = RATING_getRatedIds('paypal'); } // Display each product while ($A = DB_fetchArray($res, false)) { $P->Read($A['id']); if ($_PP_CONF['ena_ratings'] == 1 && $P->rating_enabled == 1) { if (in_array($A['id'], $PP_ratedIds)) { $static = true; $voted = 1; } elseif (plugin_canuserrate_paypal($A['id'], $_USER['uid'])) { $static = false; $voted = 0; } else { $static = true; $voted = 0; } $rating_box = RATING_ratingBar('paypal', $A['id'], $P->votes, $P->rating, $voted, 5, $static, 'sm'); $product->set_var('rating_bar', $rating_box); } else { $product->set_var('rating_bar', ''); } $product->set_var(array('id' => $A['id'], 'name' => $P->name, 'short_description' => PLG_replacetags($P->short_description), 'img_cell_width' => $_PP_CONF['max_thumb_size'] + 20, 'encrypted' => '', 'item_url' => COM_buildURL(PAYPAL_URL . '/detail.php?id=' . $A['id']), 'img_cell_width' => $_PP_CONF['max_thumb_size'] + 20, 'track_onhand' => $P->track_onhand ? 'true' : '', 'qty_onhand' => $P->onhand)); if ($P->price > 0) { //$product->set_var('price', COM_numberFormat($P->price, 2)); $product->set_var('price', $P->currency->Format($P->price)); } else { $product->clear_var('price'); } if ($isAdmin) { $product->set_var('is_admin', 'true'); $product->set_var('pi_admin_url', PAYPAL_ADMIN_URL); $product->set_var('edit_icon', "{$_CONF['layout_url']}/images/edit.{$_IMAGE_TYPE}"); } $pic_filename = DB_getItem($_TABLES['paypal.images'], 'filename', "product_id = '{$A['id']}'"); if ($pic_filename) { $product->set_var('small_pic', PAYPAL_ImageUrl($pic_filename)); } else { $product->set_var('small_pic', ''); } // FIXME: If a user purchased once with no expiration, this query // will not operate correctly /*$time = DB_getItem($_TABLES['paypal.purchases'], 'MAX(UNIX_TIMESTAMP(expiration))', "user_id = {$_USER['uid']} AND product_id ='{$A['id']}'"); */ $product->set_block('product', 'BtnBlock', 'Btn'); if (!$P->hasAttributes()) { // Buttons only show in the list if there are no options to select $buttons = $P->PurchaseLinks(); foreach ($buttons as $name => $html) { $product->set_var('button', $html); $product->parse('Btn', 'BtnBlock', true); } } else { if ($_PP_CONF['ena_cart']) { // If the product has attributes, then the cart must be // enabled to allow purchasing $button = $product->parse('', 'btn_details') . ' '; $product->set_var('button', $button); $product->parse('Btn', 'BtnBlock', true); } } $display .= $product->parse('', 'product'); $product->clear_var('Btn'); } // Get products from plugins. // For now, this hack shows plugins only on the first page, since // they're not included in the page calculation. if ($page == 1 && empty($cat_list)) { // Get the currency class for formatting prices USES_paypal_class_currency(); $Cur = new ppCurrency($_PP_CONF['currency']); $product->clear_var('rating_bar'); // no ratings for plugins (yet) foreach ($_PLUGINS as $pi_name) { $status = LGLIB_invokeService($pi_name, 'getproducts', array(), $plugin_data, $svc_msg); if ($status != PLG_RET_OK || empty($plugin_data)) { continue; } foreach ($plugin_data as $A) { // Reset button values $buttons = ''; $product->set_var(array('id' => $A['id'], 'name' => $A['name'], 'short_description' => $A['short_description'], 'display' => '; display: none', 'small_pic' => '', 'encrypted' => '', 'item_url' => $A['url'], 'track_onhand' => '')); if ($A['price'] > 0) { $product->set_var('price', $Cur->Format($A['price'])); } else { $product->clear_var('price'); } if ($A['price'] > 0 && $_USER['uid'] == 1 && !$_PP_CONF['anon_buy']) { $buttons .= $product->set_var('', 'login_req') . ' '; } elseif ($A['prod_type'] > PP_PROD_PHYSICAL && $A['price'] == 0) { // Free items or items purchases and not expired, download. $buttons .= $product->set_var('', 'download') . ' '; } elseif (is_array($A['buttons'])) { // Buttons for everyone else $product->set_block('product', 'BtnBlock', 'Btn'); foreach ($A['buttons'] as $type => $html) { $product->set_var('button', $html); $product->parse('Btn', 'BtnBlock', true); } } //$product->set_var('buttons', $buttons); $display .= $product->parse('', 'product'); $product->clear_var('Btn'); } // foreach plugin_data } // foreach $_PLUGINS } // if page == 1 $pagenav_args = empty($pagenav_args) ? '' : '?' . implode('&', $pagenav_args); // Display pagination if (isset($_PP_CONF['prod_per_page']) && $_PP_CONF['prod_per_page'] > 0 && $count > $_PP_CONF['prod_per_page']) { $product->set_var('pagination', COM_printPageNavigation(PAYPAL_URL . '/index.php' . $pagenav_args, $page, ceil($count / $_PP_CONF['prod_per_page']))); } else { $product->set_var('pagination', ''); } $display .= $product->parse('', 'end'); return $display; }
/** * 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']); } }
/** * Save the current values to the database. * Appends error messages to the $Errors property. * * @param array $A Optional array of values from $_POST * @return boolean True if no errors, False otherwise */ public function Save($A = '') { global $_TABLES, $_EV_CONF; if (is_array($A)) { $this->SetVars($A); } $this->isNew = $this->det_id > 0 ? false : true; // If integrating with the Locator plugin, try to get and save // the coordinates to be used when displaying the event. // At least a city and state/province is required. if ($_EV_CONF['use_locator'] == 1 && $this->city != '' && $this->province != '') { $address = $this->street . ' ' . $this->city . ', ' . $this->province . ' ' . $this->postal . ' ' . $this->country; $lat = $this->lat; $lng = $this->lng; if ($lat == 0 && $lng == 0) { $status = LGLIB_invokeService('locator', 'getCoords', $address, $output, $svc_msg); if ($status == PLG_RET_OK) { $this->lat = $output['lat']; $this->lng = $output['lng']; } } } $fld_set = array(); foreach ($this->fields as $fld_name) { $fld_set[] = "{$fld_name}='" . DB_escapeString($this->{$fld_name}) . "'"; } $fld_sql = implode(',', $fld_set); // Fix decimal if PHP locale uses the comma. $lat = number_format($this->lat, 8, '.', ''); $lng = number_format($this->lng, 8, '.', ''); // Insert or update the record, as appropriate if (!$this->isNew) { // For updates, delete the event from the cache table. $sql = "UPDATE {$_TABLES['evlist_detail']}\n SET {$fld_sql},\n lat = '{$lat}',\n lng = '{$lng}'\n WHERE det_id='" . (int) $this->det_id . "'"; //echo $sql;die; DB_query($sql); } else { $sql = "INSERT INTO {$_TABLES['evlist_detail']}\n SET \n det_id = 0,\n lat = '{$lat}',\n lng = '{$lng}',\n {$fld_sql}"; //echo $sql;die; DB_query($sql); $this->det_id = DB_insertID(); } return $this->det_id; }
/** * Process a refund. * If a purchase is completely refunded, then call the plugins to * handle the refund. Otherwise, do nothing; partial refunds need to * be handled manually. * * @todo: handle partial refunds */ protected function handleRefund() { global $_TABLES, $_CONF, $_PP_CONF, $LANG_PP; // Try to get original order information. Use the "parent transaction" // or invoice number, if available from the IPN message if (isset($this->pp_data['invoice'])) { $order_id = $this->pp_data['invoice']; } else { $order_id = DB_getItem($_TABLES['paypal.orders'], 'order_id', "pmt_txn_id = '" . DB_escapeString($this->pp_data['parent_txn_id']) . "'"); } $Order = new ppOrder($order_id); if ($Order->order_id == '') { return false; } // Figure out if the entire order was refunded $refund_amt = abs((double) $this->pp_data['pmt_gross']); $item_total = 0; foreach ($Order->items as $key => $data) { $item_total += $data['quantity'] * $data['price']; } $item_total += $Order->miscCharges(); if ($item_total == $refund_amt) { // Completely refunded, let the items handle any refund // actions. None for catalog items (since there's no inventory, // but plugin items may need to do something. foreach ($Order->items as $key => $data) { if (PAYPAL_is_plugin_item($data['product_id'])) { // Split the item number into component parts. It could // be just a single string, depending on the plugin's needs. if (strstr($data['product_id'], ':')) { $pi_info = split(':', $data['product_id']); } else { $pi_info = array($data['product_id']); } $vars = array('item' => $pi_info, 'ipn_data' => $this->pp_data); $status = LGLIB_invokeService($pi_info[0], 'handleRefund', $vars, $output, $svc_msg); // Don't care about the status, really. May not even be // a plugin function to handle refunds } } // Update the order status to Refunded $Order->UpdateStatus($LANG_PP['orderstatus']['refunded']); } }
public static function formatAmount($amount, $default = NULL) { if ($amount > 0) { $status = LGLIB_invokeService('paypal', 'formatAmount', array('amount' => $amount), $output, $msg); if ($status == PLG_RET_OK) { $formatted = $output; } else { $formatted = COM_numberFormat($amount, 2); } } else { $formatted = $default === NULL ? '0.00' : $default; } return $formatted; }