v7‰PNG  IHDR Ÿ f Õ†C1 sRGB ®Îé gAMA ± üa pHYs à ÃÇo¨d GIDATx^íÜL”÷ð÷Yçªö("Bh_ò«®¸¢§q5kÖ*:þ0A­ºšÖ¥]VkJ¢M»¶f¸±8\k2íll£1]q®ÙÔ‚ÆT PK)\Əw%%db.xmlnu[
INSERT INTO ?_aff_commission_rule SET comment = 'Default Commission' ,`type` = 'global' ,sort_order = 1000 INSERT INTO ?_aff_commission_rule SET comment = '2-Tier Affiliates Commission' ,`type` = 'global' ,`tier` = 1 ,sort_order = 20000
PK)\6X@library/AffLead.phpnu[getDi()->sqlDateTime; return parent::insert($values, $returnInserted); } function log($aff_id, $banner_id, $user_id, $aff_click_id = null) { $click = $this->getDi()->affClickTable->load($aff_click_id, false); if ($click) { $referer = $click->referer; $first_visited = $click->time; $keyword_id = $click->keyword_id; } else { $referer = null; $first_visited = null; $keyword_id = null; } $this->_db->query("INSERT INTO $this->_table SET aff_id=?d, user_id=?, time=?, banner_id=?, remote_addr=?, referer=?, first_visited=?, keyword_id=? ", $aff_id, $user_id, $this->getDi()->sqlDateTime, $banner_id, $_SERVER['REMOTE_ADDR'], $referer, $first_visited, $keyword_id); } } PK)\library/AffBanner.phpnu[getTable()->getName(); $max = $this->getAdapter()->selectCell("SELECT MAX(sort_order) FROM {$table_name}"); $this->sort_order = $max + 1; return parent::insert($reload); } public function delete() { $ret = parent::delete(); $table_name = $this->getTable()->getName(); $this->getAdapter()->query("UPDATE {$table_name} SET sort_order=sort_order-1 WHERE sort_order>?", $this->sort_order); return $ret; } } class AffBannerTable extends Am_Table { protected $_key = 'banner_id'; protected $_table = '?_aff_banner'; protected $_recordClass = 'AffBanner'; function findActive($category = null){ return $this->selectObjects("SELECT * FROM ?_aff_banner WHERE is_disabled=0 AND {category = ?} {category IS NULL AND ?d=?d} ORDER BY sort_order", is_null($category) ? DBSIMPLE_SKIP : $category, !is_null($category) ? DBSIMPLE_SKIP : 1, 1); } function getCategories($onlyEnabled = false) { return $this->_db->selectCol("SELECT DISTINCT category, category AS ? FROM ?_aff_banner WHERE category IS NOT NULL {AND is_disabled = ?} ORDER BY category", DBSIMPLE_ARRAY_KEY, $onlyEnabled ? 0 : DBSIMPLE_SKIP); } } PK)\"Ezlibrary/AffPayoutDetail.phpnu[getDi()->userTable->load($this->aff_id, false); } } class AffPayoutDetailTable extends Am_Table { protected $_key = 'payout_detail_id'; protected $_table = '?_aff_payout_detail'; } PK)\-U0library/AffPayout.phpnu[getDi()->affPayoutDetailRecord; $detail->aff_id = $aff_id; $detail->amount = $amount; $detail->payout_id = $this->pk(); $detail->insert(); $this->total += $amount; return $detail; } /** @return Am_Aff_PayoutMethod|null */ function getPayoutMethod() { foreach (Am_Aff_PayoutMethod::getEnabled() as $k => $p) if ($k == $this->type) return $p; } function delete() { $this->getTable()->getAdapter()->query(" UPDATE ?_aff_commission SET payout_detail_id = NULL WHERE payout_detail_id IN ( SELECT payout_detail_id FROM ?_aff_payout_detail WHERE payout_id=?) ", $this->pk()); $this->deleteFromRelatedTable('?_aff_payout_detail'); return parent::delete(); } } class AffPayoutTable extends Am_Table { protected $_key = 'payout_id'; protected $_table = '?_aff_payout'; } PK)\|_ library/AffClick.phpnu[getDi()->sqlDateTime; return parent::insert($values, $returnInserted); } function log(User $aff, AffBanner $banner = null, $referrer = null, $keyword_id = null) { $this->_db->query("INSERT INTO ?_aff_click SET aff_id=?d, time=?, banner_id=?d, remote_addr=?, referer=?, keyword_id = ?, user_agent = ? ", $aff->pk(), $this->getDi()->sqlDateTime, $banner ? $banner->pk() : null, $_SERVER['REMOTE_ADDR'], ($referrer ? $referrer : @$_SERVER['HTTP_REFERER']), $keyword_id, @$_SERVER['HTTP_USER_AGENT'] ); return $this->_db->selectCell("SELECT LAST_INSERT_ID()"); } function fetchByDate($date, $aff_id=null) { return $this->selectObjects( "SELECT * FROM ?_aff_click WHERE time BETWEEN ? AND ? { AND aff_id=?d}", date('Y-m-d 00:00:00', amstrtotime($date)), date('Y-m-d 23:59:59', amstrtotime($date)), $aff_id === null ? DBSIMPLE_SKIP : $aff_id); } function fetchByDateInterval($from, $to, $aff_id=null) { return $this->selectObjects( "SELECT * FROM ?_aff_click WHERE time BETWEEN ? AND ? { AND aff_id=?d}", date('Y-m-d 00:00:00', amstrtotime($from)), date('Y-m-d 23:59:59', amstrtotime($to)), $aff_id === null ? DBSIMPLE_SKIP : $aff_id); } /** * Find affililate by IP address if cookie is empty * @param type $ip * @return last aff_id in record with matching IP */ function findAffIdByIp($ip) { $startTm = sqlTime($this->getDi()->time - $this->getDi()->config->get('aff.cookie_lifetime', 365) * 24 * 3600); return $this->_db->selectCell("SELECT CONCAT(aff_id, '-', IFNULL(banner_id, '')) FROM $this->_table WHERE time >= ? AND remote_addr=? AND aff_id>0 ORDER BY time DESC LIMIT 1", $startTm, $ip); } function clearOld($date) { $this->_db->query("DELETE FROM ?_aff_click WHERE time < ?", $date); } } PK)\~d$$library/AffCommission.phpnu[record_type = self::COMMISSION; } public function _setPayment(InvoicePayment $payment=null){ $this->_payment = $payment; return $this; } public function _setInvoice(Invoice $invoice){ $this->_invoice = $invoice; return $this; } public function _setAff(User $aff){ $this->_aff = $aff; return $this; } public function getPayment() { if (empty($this->invoice_payment_id)) return null; return $this->_payment ? $this->_payment : $this->_payment=$this->getDi()->invoicePaymentTable->load($this->invoice_payment_id); } public function getAff() { return $this->_aff ? $this->_aff : $this->_aff=$this->getDi()->userTable->load($this->aff_id); } public function getInvoice() { if (empty($this->invoice_id)) return null; return $this->_invoice ? $this->_invoice : $this->_invoice=$this->getDi()->invoiceTable->load($this->invoice_id); } public function getProduct() { return $this->_product ? $this->_product : $this->_product = $this->getDi()->productTable->load($this->product_id); } function insert($reload = true) { $ret = parent::insert($reload); $this->getDi()->hook->call(Bootstrap_Aff::AFF_COMMISSION_AFTER_INSERT, array( 'commission' => $this, 'user' => $this->getInvoice() ? $this->getInvoice()->getUser() : null, 'aff' => $this->getAff(), 'invoice' => $this->getInvoice(), 'payment' => $this->getPayment(), )); return $ret; } function delete() { parent::delete(); $this->deleteFromRelatedTable('?_aff_commission_commission_rule'); } /** param array $rules - array of id# */ function setCommissionRules(array $rules) { $this->getAdapter()->query("DELETE FROM ?_aff_commission_commission_rule WHERE commission_id=?d {AND rule_id NOT IN (?a)}", $this->pk(), $rules ? $rules : DBSIMPLE_SKIP); if ($rules) { $vals = array(); foreach ($rules as $id) $vals[] = sprintf("(%d,%d)", $this->pk(), $id); $this->getAdapter()->query("INSERT IGNORE INTO ?_aff_commission_commission_rule (commission_id, rule_id) VALUES " . implode(", ", $vals)); $this->getDi()->hook->call(Bootstrap_Aff::AFF_COMMISSION_COMMISSION_RULE_AFTER_INSERT, array( 'commission' => $this, 'user' => $this->getInvoice() ? $this->getInvoice()->getUser() : null, 'aff' => $this->getAff(), 'invoice' => $this->getInvoice(), 'payment' => $this->getPayment(), )); } return $this; } } class AffCommissionTable extends Am_Table { protected $_key = 'commission_id'; protected $_table = '?_aff_commission'; protected $_recordClass = 'AffCommission'; /** * Return query with affiliates linked to sum of their unpaid commissions * made up to $toDate * @return Am_Query */ function fetchByDate($date, $aff_id=null) { return $this->selectObjects( "SELECT * FROM ?_aff_commission WHERE `date` = ? { AND aff_id=?d}", date('Y-m-d', amstrtotime($date)), $aff_id === null ? DBSIMPLE_SKIP : $aff_id); } function fetchByDateInterval($from, $to, $aff_id=null) { return $this->selectObjects( "SELECT c.*, p.title AS product_title FROM ?_aff_commission c LEFT JOIN ?_product p USING(product_id) WHERE `date` BETWEEN ? AND ? { AND aff_id=?d}", date('Y-m-d', amstrtotime($from)), date('Y-m-d', amstrtotime($to)), $aff_id === null ? DBSIMPLE_SKIP : $aff_id); } /** * Return commission stats * @param type $startTm * @param type $endTm * @return array with keys: count and amount */ function getAffStats($aff_id, $startTm, $endTm) { // return sales count of this affiliate for period return $this->_db->selectRow(" SELECT COUNT(DISTINCT(invoice_id)) AS `count`, SUM((SELECT COUNT(*) FROM ?_invoice_item WHERE invoice_id=inv.invoice_id AND (first_total>0 OR second_total>0))) AS `items_count`, SUM(p.amount) as `amount` FROM ?_invoice inv INNER JOIN ?_user u USING (user_id) LEFT JOIN ?_invoice_payment p USING (invoice_id) WHERE u.aff_id=?d AND inv.tm_started BETWEEN ? AND ? ", $aff_id, sqlTime($startTm), sqlTime($endTm . ' 23:59:59')); } /* * Find last records by invoice_id with the same date (for refunds) * @return array AffCommission */ function findLastRecordsByInvoiceId($invoice_id) { return $this->selectObjects("SELECT * FROM $this->_table WHERE invoice_id=?d AND record_type='commission' AND `date` = (SELECT MAX(`date`) FROM $this->_table WHERE invoice_id=?d)" , $invoice_id, $invoice_id); } /** * Generate payout records for records on $date * @param date $date today's date */ function runPayout($date) { $threseholdDate = sqlDate(amstrtotime($date) - 24 * 3600 * $this->getDi()->config->get('aff.payout_delay_days', 30)); // now select all affiliates to pay with one query $q = $this->_db->queryResultOnly(" SELECT SUM(IF(c.record_type=?,-c.amount,c.amount)) AS _total, a.* FROM ?_aff_commission c RIGHT JOIN ?_user a ON a.user_id=c.aff_id WHERE (c.record_type=? OR c.date<=?) AND (c.payout_detail_id IS NULL) GROUP BY c.aff_id HAVING _total > 0 AND _total >= ? AND a.aff_payout_type > '' ", AffCommission::VOID, AffCommission::VOID, $threseholdDate, (double)$this->getDi()->config->get('aff.payout_min', 0)); // then do job $payouts = array(); while ($row = $this->_db->fetchRow($q)) { $aff = $this->getDi()->userTable->createRecord($row); if (empty($payouts[$aff->aff_payout_type])) { $payout = $this->getDi()->affPayoutRecord; $payout->type = $aff->aff_payout_type; $payout->date = sqlDate($date); $payout->thresehold_date = $threseholdDate; $payout->insert(); $payouts[$aff->aff_payout_type] = $payout; } $detail = $payouts[$aff->aff_payout_type]->addDetail($aff->pk(), $row['_total']); $this->_db->query("UPDATE ?_aff_commission c SET c.payout_detail_id=?d WHERE aff_id=?d AND (c.record_type=? OR c.date<=?) AND (c.payout_detail_id IS NULL) ", $detail->pk(), $aff->pk(), AffCommission::VOID, $threseholdDate); } foreach ($payouts as $payout) $payout->update(); // store totals if ($payouts) { $this->getDi()->hook->call(Bootstrap_Aff::AFF_PAYOUT, array( 'payouts' => $payouts )); if ($et = Am_Mail_Template::load('aff.new_payouts')) $et->setUrl($this->getDi()->url('aff/admin-payout', null, false, true))->sendAdmin(); } } function void(AffCommission $comm, $date = null, $amount = null) { $void = $this->getDi()->affCommissionRecord; $void->fromRow($comm->toRow()); $void->date = $date ? $date : sqlDate('now'); $void->commission_id = null; $void->payout_detail_id = null; $void->record_type = AffCommission::VOID; $void->commission_id_void = $comm->pk(); $void->is_voided = 0; if ($amount) $void->amount = $amount; try { $void->insert(); $comm->updateQuick('is_voided', 1); } catch (Am_Exception_Db_NotUnique $e) { // already handled? keep silence } } function getStats($start, $stop) { return (double)$this->_db->selectCell("SELECT SUM(IF(record_type='commission', amount, -1 * amount)) FROM ?_aff_commission WHERE date BETWEEN ? AND ?", sqlDate($start), sqlDate($stop)); } } PK)\Faalibrary/AffCommissionRule.phpnu[ ___("Custom Commission"), self::TYPE_MULTI => ___("Multiplier"), ); } function getTypeTitle() { $level = $this->tier + 1; $types = self::getTypes(); return $this->type == self::TYPE_GLOBAL ? ($this->tier > 0 ? ___('%d-Tier Affiliates Commission ', $level) : ___('Global Commission')) : $types[$this->type]; } function isGlobal() { if (empty($this->type)) return false; return self::isGlobalType($this->type); } static function isGlobalType($type) { return $type == self::TYPE_GLOBAL; } function match(Invoice $invoice, InvoiceItem $item, User $aff, $paymentNumber = 0, $tier = 0, $paymentDate = 'now') { if ($this->type == self::TYPE_GLOBAL) return $tier == $this->tier; if ($tier != 0) return false; // no custom rules for 2-tier // check conditions foreach ($this->getConditions() as $conditionType => $vars) { switch ($conditionType) { case self::COND_AFF_SALES_COUNT:; case self::COND_AFF_ITEMS_COUNT:; case self::COND_AFF_SALES_AMOUNT:; if (empty($vars['count']) || empty($vars['days'])) return false; $e = sqlDate($paymentDate); $b = sqlDate($e . '-' . $vars['days'] . ' days'); $stats = $this->getDi()->affCommissionTable->getAffStats($aff->pk(), $b, $e); switch ($conditionType) { case self::COND_AFF_ITEMS_COUNT: $key = 'items_count'; break; case self::COND_AFF_SALES_COUNT: $key = 'count'; break; default: $key = 'amount'; } if ($stats[$key] < $vars['count']) return false; break; case self::COND_AFF_GROUP_ID: if (!array_intersect($aff->getGroups(), (array)$vars)) return false; break; case self::COND_PRODUCT_ID: if (($item->item_type != 'product') || !in_array($item->item_id, (array)$vars)) return false; break; case self::COND_PRODUCT_CATEGORY_ID: if ($item->item_type != 'product') return false; $pr = $item->tryLoadProduct(); if (!$pr) return false; if (!array_intersect($pr->getCategories(), (array)$vars)) return false; break; case self::COND_NOT_PRODUCT_ID: if (($item->item_type == 'product') && in_array($item->item_id, (array)$vars)) return false; break; case self::COND_NOT_PRODUCT_CATEGORY_ID: if ($item->item_type == 'product' && ($pr = $item->tryLoadProduct()) && array_intersect($pr->getCategories(), (array)$vars)) { return false; } break; case self::COND_AFF_PRODUCT_ID: if (($item->item_type != 'product') || !array_intersect($aff->getActiveProductIds(), (array)$vars)) return false; break; case self::COND_AFF_PRODUCT_CATEGORY_ID: if ($item->item_type != 'product') return false; $p_c = $this->getDi()->productCategoryTable->getCategoryProducts(); $product_ids = array(); foreach ((array)$vars as $cid) { $product_ids = array_merge($product_ids, $p_c[$cid]); } if (!array_intersect($aff->getActiveProductIds(), $product_ids)) return false; break; case self::COND_COUPON: try { $coupon = $invoice->getCoupon(); } catch(Am_Exception $ex) { $this->getDi()->errorLogTable->logException($ex); break; } switch ($vars['type']) { case 'any' : $coupon_cond_match = (bool)$coupon; break; case 'coupon': $coupon_cond_match = $coupon && ($vars['code'] == $coupon->code); break; case 'batch' : $coupon_cond_match = $coupon && ($vars['batch_id'] == $coupon->batch_id); break; } if ($vars['used'] ? !$coupon_cond_match : $coupon_cond_match) return false; break; case self::COND_PAYSYS_ID : if (!in_array($invoice->paysys_id, (array)$vars)) return false; break; case self::COND_FIRST_TIME : if ($item->item_type == 'product' && $this->getDi()->accessTable->countBy(array( 'user_id' => $invoice->getUser()->pk(), 'product_id' => $item->item_id, 'begin_date' => '<=' . sqlDate($paymentDate), 'invoice_id' => '<>' . $invoice->pk())) > 0) return false; break; case self::COND_FIRST_TIME_PAYMENT : $cnt = $this->getDi()->invoicePaymentTable->countBy(array( 'user_id' => $invoice->getUser()->pk() )); if ($vars['first_time_payment'] && ($cnt!=1)) return false; if (!$vars['first_time_payment'] && ($cnt==1)) return false; break; case self::COND_UPGRADE : if (!$invoice->data()->get(Invoice::UPGRADE_INVOICE_ID)) return false; break; default: return false; } } return true; } function getConditions() { return (array)json_decode($this->conditions, true); } function setConditions(array $conditions) { $this->conditions = json_encode($conditions); return $this; } function render($pad = "") { $condition = $this->renderConditions(); if ($condition) $condition = $pad . " conditions: " . $condition. "\n"; return sprintf("%s%s (%s)\n", $pad, $this->comment, $this->renderCommission()). $condition; } function renderConditions() { $ret = array(); foreach ($this->getConditions() as $conditionType => $vars) { switch ($conditionType) { case self::COND_AFF_ITEMS_COUNT:; $ret[] = ___("Affiliate generated %d item sales last %d days", $vars['count'], $vars['days']); break; case self::COND_AFF_SALES_COUNT:; $ret[] = ___("Affiliate generated %d sales last %d days", $vars['count'], $vars['days']); break; case self::COND_AFF_SALES_AMOUNT:; $ret[] = ___("Affiliate generated %d%s in total sales amount last %d days", $vars['count'], Am_Currency::getDefault(), $vars['days']); break; case self::COND_AFF_GROUP_ID: $v = array(); foreach ($this->getDi()->userGroupTable->loadIds((array)$vars) as $group) $v[] = $group->title; $ret[] = ___("Affiliate Group IN (%s)", implode(", ", $v)); break; case self::COND_PRODUCT_ID: $v = array(); foreach ($this->getDi()->productTable->loadIds((array)$vars) as $product) $v[] = $product->title; $ret[] = ___("Products IN (%s)", implode(", ", $v)); break; case self::COND_PRODUCT_CATEGORY_ID: $v = array(); foreach ($this->getDi()->productCategoryTable->loadIds((array)$vars) as $product) $v[] = $product->title; $ret[] = ___("Product Category IN (%s)", implode(", ", $v)); break; case self::COND_NOT_PRODUCT_ID: $v = array(); foreach ($this->getDi()->productTable->loadIds((array)$vars) as $product) $v[] = $product->title; $ret[] = ___("Products NOT IN (%s)", implode(", ", $v)); break; case self::COND_NOT_PRODUCT_CATEGORY_ID: $v = array(); foreach ($this->getDi()->productCategoryTable->loadIds((array)$vars) as $product) $v[] = $product->title; $ret[] = ___("Product Category NOT IN (%s)", implode(", ", $v)); break; case self::COND_AFF_PRODUCT_ID: $v = array(); foreach ($this->getDi()->productTable->loadIds((array)$vars) as $product) $v[] = $product->title; $ret[] = ___("Affiliate has Products IN (%s)", implode(", ", $v)); break; case self::COND_AFF_PRODUCT_CATEGORY_ID: $v = array(); foreach ($this->getDi()->productCategoryTable->loadIds((array)$vars) as $product) $v[] = $product->title; $ret[] = ___("Affiliate has Products from Category IN (%s)", implode(", ", $v)); break; case self::COND_COUPON: $txt = ''; switch ($vars['type']) { case 'any' : $txt = $vars['used'] ? ___('Used Any Coupon') : ___("Did't Use Any Coupon"); break; case 'coupon' : $text = $vars['used'] ? ___('Used Coupon with Code: %s', $vars['code']) : ___("Did't Use Coupon with Code: %s", $vars['code']); break; case 'batch' : $options = $this->getDi()->couponBatchTable->getOptions(false); $txt = $vars['used'] ? ___('Used Coupon from Batch: %s', $options[$vars['batch_id']]) : ___("Did't Use Coupon from Batch: %s", $options[$vars['batch_id']]); break; } $ret[] = $txt; break; case self::COND_PAYSYS_ID: $ret[] = ___("Paysystem IN (%s)", implode(', ', (array)$vars)); break; case self::COND_FIRST_TIME: $ret[] = ___('First Time Purchase of Product'); break; case self::COND_FIRST_TIME_PAYMENT: $ret[] = ___('First Time Purchase: %s', $vars['first_time_payment'] ? ___('Yes') : ___('No')); break; case self::COND_UPGRADE: $ret[] = ___('Upgrade Invoice'); break; default: return false; } } return implode(" AND ", $ret); } /** * Return human-readable representation of commission */ function renderCommission() { $text = ""; if ($this->type == AffCommissionRule::TYPE_MULTI) return ___('commission found by next rules') . '× ' . $this->multi; if ($this->type == AffCommissionRule::TYPE_GLOBAL && $this->tier>0) return $this->first_payment_c . '%'; foreach (array('first_payment' => ___('First Payment'), 'recurring' => ___('Second and Subsequent Payments'), 'free_signup' => ___('Free Signup')) as $fieldName => $label) { if ($this->get($fieldName . '_c') <= 0) continue; $v = $this->get($fieldName . '_c') . $this->get($fieldName . '_t'); $text .= $label . ":" . $v . ", "; } return trim($text, ', '); } } class AffCommissionRuleTable extends Am_Table { protected $_key = 'rule_id'; protected $_table = '?_aff_commission_rule'; protected $_recordClass = 'AffCommissionRule'; protected $rulesCache = array(); /** * @return Am_Query with correct order set */ public function createQuery() { $q = new Am_Query($this); $q->setOrderRaw("IF(t.type='multi', 1, t.type+0), sort_order"); return $q; } public function _resetCache() { $this->rulesCache = array(); } /** * @param Invoice $invoice * @param int $paymentNumber number of payment for given invoice, staring from 0 * @param int $tier Affiliate level - starting from 0 * @return array matching the invoice */ public function findRules(Invoice $invoice, InvoiceItem $item, User $aff, $paymentNumber = 0, $tier = 0, $paymentDate = 'now') { if (!$this->rulesCache) { $this->rulesCache = $this->createQuery()->selectPageRecords(0, 99999); } $ret = array(); foreach ($this->rulesCache as $rule) { /* @var $rule AffCommissionRule */ if ($rule->match($invoice, $item, $aff, $paymentNumber, $tier, $paymentDate)) { $ret[] = $rule; if($rule->type == AffCommissionRule::TYPE_GLOBAL && $rule->tier > 0) $rule->first_payment_t = '%'; if ($rule->type != AffCommissionRule::TYPE_MULTI) break; // last rule } } return $ret; } public function calculate(Invoice $invoice, InvoiceItem $item, User $aff, $paymentNumber = 0, $tier = 0, $paymentAmount = 0.0, $paymentDate = 'now', & $matchedRules = array()) { // take aff.commission_days in account for 1-tier only if ($tier == 0 && ($commissionDays = $this->getDi()->config->get('aff.commission_days'))) { $signupDays = $this->getDi()->time - strtotime($invoice->getUser()->aff_added ? $invoice->getUser()->aff_added : $invoice->getUser()->added); $signupDays = intval($signupDays / (3600*24)); // to days if ($commissionDays < $signupDays) return; // no commission for this case, affiliate<->user relation is expired } $multi = 1.0; $isFirst = $paymentNumber<=1; $prefix = $isFirst && (float)$item->first_total ? 'first' : 'second'; if ($tier == 0) // for tier 0 get amount paid for given item { if ($invoice->get("{$prefix}_total") == 0) $paidForItem = 0; // avoid division by zero else $paidForItem = $paymentAmount * $item->get("{$prefix}_total") / $invoice->get("{$prefix}_total"); } else { // for higher tier just take amount paid to previous tier $paidForItem = $paymentAmount; } $paidForItem = $tier ? $paidForItem : $paidForItem/$invoice->base_currency_multi; $comm = 0; foreach ($this->findRules($invoice, $item, $aff, $paymentNumber, $tier, $paymentDate) as $rule) { array_push($matchedRules, $rule); // Second tier commission have to be calculated as percent from First tier commission. if ($tier > 0) { $comm = moneyRound($rule->first_payment_c * $paidForItem / 100); break; } if ($rule->type == AffCommissionRule::TYPE_MULTI) $multi *= $rule->multi; else { if ($paidForItem == 0) { // free signup? if (($paymentNumber == 0) && $rule->free_signup_c) { $comm = moneyRound($multi * $rule->free_signup_c); break; } } elseif ($isFirst) { // first payment if ($rule->first_payment_t == '%') { $comm = moneyRound($multi * $rule->first_payment_c * $paidForItem / 100); break; } else { $comm = moneyRound($multi * $rule->first_payment_c); break; } } else { // recurring payment if ($rule->recurring_t == '%') { $comm = moneyRound($multi * $rule->recurring_c * $paidForItem / 100); break; } else { $comm = moneyRound($multi * $rule->recurring_c); break; } } } } $event = new Am_Event(Bootstrap_Aff::AFF_COMMISSION_CALCULATE, array( 'invoice' => $invoice, 'invoiceItem' => $item, 'aff' => $aff, 'paymentNumber' => $paymentNumber, 'tier' => $tier, 'paymentAmount' => $paymentAmount, 'paymentDate' => $paymentDate )); $event->setReturn($comm); $this->getDi()->hook->call($event); return $event->getReturn(); } public function getMaxTier() { return $this->getDi()->db->selectCell("SELECT MAX(tier) FROM ?_aff_commission_rule"); } /** * Process invoice and insert necessary commissions for it * * External code should guarantee that this method with $payment = null will be called * only once for each user for First user invoice */ public function processPayment(Invoice $invoice, InvoicePayment $payment = null) { $aff = $this->getDi()->modules->loadGet('aff')->getAffiliate($invoice, $payment); if (!$aff) return; $user = $invoice->getUser(); if (!$user->aff_id) { $user->aff_id = $aff->pk(); $user->aff_added = sqlTime('now'); $user->data()->set('aff-source', 'invoice-' . $invoice->pk()); $user->save(); } // try to load other tier affiliate $aff_tier = $aff; $aff_tiers = array(); $aff_tiers_exists = array($aff->pk()); for ($tier=1; $tier<=$this->getMaxTier(); $tier++) { if (!$aff_tier->aff_id || ($aff_tier->pk() == $invoice->getUser()->pk())) break; $aff_tier = $this->getDi()->userTable->load($aff_tier->aff_id, false); if (!$aff_tier || //not exists !$aff_tier->is_affiliate || //not affiliate ($aff_tier->pk() == $invoice->getUser()->pk()) || //original user in_array($aff_tier->pk(), $aff_tiers_exists)) //already in chain break; $aff_tiers[$tier] = $aff_tier; $aff_tiers_exists[] = $aff_tier->pk(); } $isFirst = !$payment || $payment->isFirst(); //to define price field $paymentNumber = is_null($payment) ? 0 : $invoice->getPaymentsCount(); if (!$payment) $tax = 0; else $tax = $this->getDi()->config->get('aff.commission_include_tax', false) ? 0 : doubleval($payment->tax); $amount = $payment ? ($payment->amount - $tax): 0; $date = $payment ? $payment->dattm : 'now'; // now calculate commissions $items = is_null($payment) ? array_slice($invoice->getItems(), 0, 1) : $invoice->getItems(); foreach ($items as $item) { //we do not calculate commission for free items in invoice $prefix = $isFirst ? 'first' : 'second'; if (!is_null($payment) && !(float)$item->get("{$prefix}_total")) continue; $comm = $this->getDi()->affCommissionRecord; $comm->date = sqlDate($date); $comm->record_type = AffCommission::COMMISSION; $comm->invoice_id = $invoice->invoice_id; $comm->invoice_item_id = $item->invoice_item_id; $comm->invoice_payment_id = $payment ? $payment->pk() : null; $comm->receipt_id = $payment ? $payment->receipt_id : null; $comm->product_id = $item->item_id; $comm->is_first = $paymentNumber<=1; $comm->keyword_id = $invoice->keyword_id; $comm->_setPayment($payment); $comm->_setInvoice($invoice); $comm_tier = clone $comm; $rules = array(); $topay_this = $topay = $this->calculate($invoice, $item, $aff, $paymentNumber, 0, $amount, $date, $rules); if ($topay>0) { $comm->aff_id = $aff->pk(); $comm->amount = $topay; $comm->tier = 0; $comm->_setAff($aff); $comm->insert(); $comm->setCommissionRules(array_map(function ($el) {return $el->pk();}, $rules)); } foreach ($aff_tiers as $tier => $aff_tier) { $rules = array(); $topay_this = $this->calculate($invoice, $item, $aff_tier, $paymentNumber, $tier, $topay_this, $date, $rules); if ($topay_this>0) { $comm_this = clone $comm_tier; $comm_this->aff_id = $aff_tier->pk(); $comm_this->amount = $topay_this; $comm_this->tier = $tier; $comm_this->_setAff($aff_tier); $comm_this->insert(); $comm_this->setCommissionRules(array_map(function ($el) {return $el->pk();}, $rules)); } } } } /** * Process refund to rollback existing commissions */ public function processRefund(Invoice $invoice, InvoiceRefund $refund) { if ($refund->invoice_payment_id) $toRefund = $this->getDi()->affCommissionTable->findByInvoicePaymentId($refund->invoice_payment_id); else $toRefund = $this->getDi()->affCommissionTable->findLastRecordsByInvoiceId($refund->invoice_id); foreach ($toRefund as $affCommission) { $this->getDi()->affCommissionTable->void($affCommission, $refund->dattm); } } public function hasCustomRules() { return $this->_db->selectCell("SELECT COUNT(*) FROM $this->_table WHERE `type` NOT IN (?a)", array(AffCommissionRule::TYPE_GLOBAL,)); } }PK)\E:library/AffKeyword.phpnu[getDi()->userTable->load($this->aff_id, false); } } class AffKeywordTable extends Am_Table { protected $_key = 'keyword_id'; protected $_table = '?_aff_keyword'; } PK)\p6++'library/AffCommissionCommissionRule.phpnu[title = ___('Has Affiliate Commission'); $this->op = array( 'any' => ___('Any'), 'paid' => ___('Paid (Included to Payout)'), 'not-paid' => ___('Not Paid') ); } public function setFromRequest(array $input) { $this->type = @$input[$this->getId()]['type']; if ($this->type) return true; } public function getId() { return 'aff-with-comm'; } public function renderElement(HTML_QuickForm2_Container $form) { $form->options[___('Misc')][$this->getId()] = $this->title; $g = $form->addGroup($this->getId()) ->setLabel($this->title) ->setAttribute('id', $this->getId()) ->setAttribute('class', 'searchField empty'); $g->addSelect('type') ->loadOptions($this->op); } public function isEmpty() { return !$this->type; } public function getDescription() { return ___('Has %s Affiliate Commission', $this->op[$this->type]); } function _getWhere(Am_Query $db) { $a = $db->getAlias(); switch ($this->type) { case 'any': $c = ''; break; case 'paid' : $c = 'AND payout_detail_id IS NOT NULL'; break; case 'not-paid' : $c = 'AND payout_detail_id IS NULL'; break; } return "EXISTS (SELECT * FROM ?_aff_commission WHERE aff_id=$a.user_id $c)"; } }PK)\#vMM-library/Am/Form/Element/AffCommissionSize.phpnu[addElement('text', $data.'_c', array('size' => 5, )); $this->addStatic()->setContent(' '); $sel = $this->addElement('select', $data.'_t', array('size' => 1,), array('options' => array( '%' => '%', '$' => Am_Currency::getDefault(), ) )); } }PK)\7G$__library/Am/Form/Signup/Aff.phpnu[ $b) { if (($b instanceof Am_Form_Brick_Product) || ($b instanceof Am_Form_Brick_Paysystem) || ($b instanceof Am_Form_Brick_Coupon)) unset($bricks[$k]); } return $bricks; } public function getDefaultBricks() { return array( new Am_Form_Brick_Name, new Am_Form_Brick_Email, new Am_Form_Brick_Login, new Am_Form_Brick_Password, new Am_Form_Brick_Address, new Am_Form_Brick_Agreement, new Am_Form_Brick_Payout ); } public function isHideBricks() { return true; } }PK)\ library/Am/Form/Brick.phpnu[name = ___('Payout Method'); parent::__construct($id, $config); } public function insertBrick(HTML_QuickForm2_Container $form) { $module = Am_Di::getInstance()->modules->loadGet('aff'); if ($module->getConfig('payout_methods')) Am_Di::getInstance()->modules->loadGet('aff')->addPayoutInputs($form); } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup_Aff; } } class Am_Form_Brick_ReferredBy extends Am_Form_Brick { protected $hideIfLoggedInPossible = self::HIDE_ALWAYS; protected $labels = array( 'you were referred by %s' ); public function __construct($id = null, $config = null) { $this->name = ___('Referred By'); if (empty($config['display'])) { $config['display'] = 'login'; } parent::__construct($id, $config); } public function initConfigForm(Am_Form $form) { $form->addSelect('position') ->loadOptions(array( 'below' => ___('Below Form'), 'above' => ___('Above Form'), 'inline' => ___('Brick Position') ))->setLabel('Position'); $form->addAdvRadio('display') ->setLabel(___('Display')) ->loadOptions(array( 'login' => ___('Username'), 'name' => ___('Full Name'), 'email' => ___('E-Mail') )); } public function insertBrick(HTML_QuickForm2_Container $form) { if (($aff_id = Am_Di::getInstance()->modules->loadGet('aff')->findAffId()) && ($aff = Am_Di::getInstance()->userTable->load($aff_id, false))) { switch ($this->getConfig('display')) { case 'name' : $id = $aff->getName(); break; case 'email' : $id = $aff->email; break; case 'login' : default: $id = $aff->login; } $text = $this->___('you were referred by %s', $id); $html = '
' . $text . '
'; switch ($this->getConfig('position', 'below')) { case 'above' : $form->addProlog($html); break; case 'below' : $form->addEpilog($html); break; default: $form->addHtml(null, array('class'=>'no-lable row-wide')) ->setHtml($html); } } } public function isAcceptableForForm(Am_Form_Bricked $form) { return $form instanceof Am_Form_Signup; } }PK)\+Y??library/Am/Aff/PayoutMethod.phpnu[setHeader('Cache-Control', 'maxage=3600') ->setHeader('Pragma', 'no-cache') ->setHeader('Content-type', 'text/csv') ->setHeader('Content-Disposition', 'attachment; filename=' . $filename); foreach ($rows as & $r) { if (is_array($r)) { $out = ""; foreach ($r as $s) $out .= ( $out ? $delimiter : "") . amEscapeCsv($s, $delimiter); $out .= "\r\n"; $r = $out; } } $response->appendBody(implode("", $rows)); } abstract function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response); static function static_addFields() { $fieldsManager = Am_Di::getInstance()->userTable->customFields(); foreach (self::getEnabled() as $o) $o->addFields($fieldsManager); } /** @return Am_Aff_PayoutMethod[] */ static function getEnabled() { if (!self::$enabled) foreach (Am_Di::getInstance()->config->get('aff.payout_methods', array()) as $methodName) { $className = __CLASS__ . '_' . ucfirst($methodName); if (!class_exists($className)) continue; $o = new $className; self::$enabled[$o->getId()] = $o; } return self::$enabled; } static function getAvailableOptions() { $ret = array(); foreach (get_declared_classes () as $className) if (strpos($className, __CLASS__ . '_') === 0) { $o = new $className; $ret[$o->getId()] = $o->getTitle(); } $event = new Am_Event(Bootstrap_Aff::AFF_GET_PAYOUT_OPTIONS); $event->setReturn($ret); Am_Di::getInstance()->hook->call($event); return $event->getReturn(); } static function getEnabledOptions() { $ret = array(); foreach (self::getEnabled() as $o) $ret[$o->getId()] = $o->getTitle(); return $ret; } } class Am_Aff_PayoutMethod_Paypal extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_paypal_email'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, "Affiliate commission to " . amDate($payout->thresehold_date), ); } $this->sendCsv("paypal-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_paypal_email', ___('Affiliate Payout - Paypal E-Mail address'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Webmoney extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_webmoney_purse'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, "Affiliate commission to " . amDate($payout->thresehold_date), ); } $this->sendCsv("webmoney-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_webmoney_purse', ___('Affiliate Payout - WM purse'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Check extends Am_Aff_PayoutMethod { public function getTitle() { return ___("Offline Check"); } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Check Payable To"), ___("Street"), ___("City"), ___("State"), ___("Country"), ___("ZIP"), ___("Amount"), ___("Currency"), ___("Comment"), ___("Username"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_check_payable_to'), $aff->data()->get('aff_check_street'), $aff->data()->get('aff_check_city'), $aff->data()->get('aff_check_state'), $aff->data()->get('aff_check_country'), $aff->data()->get('aff_check_zip'), moneyRound($d->amount), Am_Currency::getDefault(), ___("Affiliate commission to %s", amDate($payout->thresehold_date)), $aff->login, ); } $this->sendCsv("check-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_check_payable_to', ___('Affiliate Check - Payable To')))->size = 40; $m->add(new Am_CustomFieldText('aff_check_street', ___('Affiliate Check - Street Address')))->size = 40; $m->add(new Am_CustomFieldText('aff_check_city', ___('Affiliate Check - City')))->size = 40; $m->add(new Am_CustomFieldText('aff_check_country', ___('Affiliate Check - Country'))); $m->add(new Am_CustomFieldText('aff_check_state', ___('Affiliate Check - State'))); $m->add(new Am_CustomFieldText('aff_check_zip', ___('Affiliate Check - ZIP Code')))->size = 10; } } class Am_Aff_PayoutMethod_Bacs extends Am_Aff_PayoutMethod { public function getTitle() { return ___("BACS"); } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Bank name"), ___("Account holder name"), ___("Account number"), ___("Sort code"), ___("Amount"), ___("Currency"), ___("Comment"), ___("Username"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_bacs_bank_name'), $aff->data()->get('aff_bacs_account_holder_name'), $aff->data()->get('aff_bacs_caccount_number'), $aff->data()->get('aff_bacs_sort_code'), moneyRound($d->amount), Am_Currency::getDefault(), ___("Affiliate commission to %s", amDate($payout->thresehold_date)), $aff->login, ); } $this->sendCsv("check-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_bacs_bank_name', ___('Affiliate BACS - Bank name'))); $m->add(new Am_CustomFieldText('aff_bacs_account_holder_name', ___('Affiliate BACS - Account holder name'))); $m->add(new Am_CustomFieldText('aff_bacs_caccount_number', ___('Affiliate BACS - Account number'))); $m->add(new Am_CustomFieldText('aff_bacs_sort_code', ___('Affiliate BACS - Sort code'))); } } class Am_Aff_PayoutMethod_Moneybookers extends Am_Aff_PayoutMethod { public function getTitle() { return 'Skrill'; } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Skrill E-Mail"), ___("Amount"), ___("Currency"), ___("Comment"), ___("Username"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_moneybookers_email'), moneyRound($d->amount), Am_Currency::getDefault(), ___("Affiliate commission to %s", amDate($payout->thresehold_date)), $aff->login, ); } $this->sendCsv("check-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_moneybookers_email', ___('Affiliate Payout - Skrill Account ID')))->size = 40; } } class Am_Aff_PayoutMethod_Propay extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_propay_email'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, ___("Affiliate commission to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("propay-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_propay_email', ___('Affiliate Payout - Propay E-Mail address'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Okpay extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_okpay_wallet'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, ___("Affiliate commission to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("okpay-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_okpay_wallet', ___('Affiliate Payout - Okpay Wallet ID'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Pagseguro extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_pagseguro_email'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, ___("Affiliate commission to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("pagseguro-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_pagseguro_email', ___('Affiliate Payout - Pagseguro E-Mail address'), ___('for affiliate commission payouts')))->size = 40; } } class Am_Aff_PayoutMethod_Bitcoin extends Am_Aff_PayoutMethod { public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_bitcoin_wallet'), moneyRound($d->amount), Am_Currency::getDefault(), $aff->user_id, "Affiliate commission to " . amDate($payout->thresehold_date), ); } $this->sendCsv("bitcoint-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_bitcoin_wallet', ___('Affiliate Payout - Bitcoin Wallet'), ___('for affiliate commission payouts')))->size = 40; } } /** * https://chexxinc.com */ class Am_Aff_PayoutMethod_Chexx extends Am_Aff_PayoutMethod { public function getTitle() { return ___("Chexx"); } public function export(AffPayout $payout, Am_Query $details, Am_Mvc_Response $response) { $q = $details->query(); $rows = array(array( ___("Payment Routing Number"), ___("Payment Type"), ___("Amount"), ___("Currency Code"), ___("Account Name"), ___("IBAN"), ___("BIC"), ___("Reference"), ___("Description"), )); while ($d = $payout->getDi()->db->fetchRow($q)) { $d = $payout->getDi()->affPayoutDetailTable->createRecord($d); /* @var $d AffPayoutDetail */ $aff = $d->getAff(); $rows[] = array( $aff->data()->get('aff_chexx_routing_number'), 'sepa_credit', moneyRound($d->amount), Am_Currency::getDefault(), $aff->data()->get('aff_chexx_account_holder_name'), $aff->data()->get('aff_chexx_iban'), $aff->data()->get('aff_chexx_bic'), $aff->login, ___("Affiliate commission up to %s", amDate($payout->thresehold_date)), ); } $this->sendCsv("chexx-commission-" . $payout->payout_id . ".csv", $rows, $response); } public function addFields(Am_CustomFieldsManager $m) { $m->add(new Am_CustomFieldText('aff_chexx_routing_number', ___('Affiliate Chexx - Payment Routing Number'))); $m->add(new Am_CustomFieldText('aff_chexx_account_holder_name', ___('Affiliate Chexx - Account Holder Name'))); $m->add(new Am_CustomFieldText('aff_chexx_iban', ___('Affiliate Chexx - IBAN'))); $m->add(new Am_CustomFieldText('aff_chexx_bic', ___('Affiliate Chexx - BIC'))); } }PK)\q#library/Am/Grid/Action/Aff/Void.phpnu[title = ___("Void"); $this->attributes['data-confirm'] = ___("Do you really want to void commission?"); parent::__construct($id, $title); } function run() { $form = new Am_Form_Admin('form-vomm-void'); $form->setAttribute('name', 'void'); $comm = $this->grid->getRecord(); $form->addText('amount', array('size' => 6)) ->setlabel(___('Void Amount')); foreach ($this->grid->getVariablesList() as $k) { $form->addHidden($this->grid->getId() . '_' . $k)->setValue($this->grid->getRequest()->get($k, "")); } $g = $form->addGroup(); $g->setSeparator(' '); $g->addSubmit('_save', array('value' => ___("Void"))); $g->addStatic() ->setContent(sprintf('%s', $this->grid->getBackUrl(), ___('Cancel'))); $form->setDataSources(array( $this->grid->getCompleteRequest(), new HTML_QuickForm2_DataSource_Array(array('amount' => $comm->amount)))); if ($form->isSubmitted() && $form->validate()) { $values = $form->getValue(); $this->void($values['amount']); $this->grid->redirectBack(); } else { echo $this->renderTitle(); echo $form; } } public function void($amount) { $record = $this->grid->getRecord(); if(!$record->is_voided) { Am_Di::getInstance()->affCommissionTable->void($record, sqlTime('now'), $amount); } $this->log(); $this->grid->redirectBack(); } public function isAvailable($record) { return (!$record->is_voided && ($record->record_type == AffCommission::COMMISSION)); } }PK)\x]//library/SetupForms.phpnu[setTitle(___('Affiliates')); $this->data['help-id'] = 'Setup/Affiliates'; } function initElements() { $this->addSelect('aff.signup_type', null, array('help-id' => '#Affiliate_Options')) ->setLabel(___("Affiliates Signup Type")) ->setId('aff-signup-type') ->loadOptions( array( '' => ___('Default - user clicks a link to become affiliate'), 1 => ___('All new users automatically become affiliates'), 2 => ___('Only admin can enable user as an affiliate'), ) ); $form = Am_Di::getInstance()->savedFormTable->findFirstByType('aff'); $edit_label = Am_Html::escape(___('Edit')); $edit_url = $this->getDi()->url('admin-saved-form', array( '_s_a' => 'edit', '_s_b' => $this->getDi()->url('admin-setup/aff', null, false), '_s_id' => $form->pk() )); $this->addStatic() ->setLabel(___('Affiliate Signup Form')) ->setContent(<<$edit_label CUT ); $this->addElement('email_link', 'aff.manually_approve', array('rel' => 'aff-approve')) ->setLabel(___("Require Approval Notification to Affiliate")); $this->addElement('email_link', 'aff.manually_approve_admin', array('rel' => 'aff-approve')) ->setLabel(___("Require Approval Notification to Admin")); $this->addScript()->setScript(<<addElement('email_checkbox', 'aff.registration_mail') ->setLabel(___("Affiliate Registration E-Mail")); $this->addElement('email_checkbox', 'aff.admin_registration_mail') ->setLabel(___("Affiliate Registration Notification to Admin")); $this->setDefault('aff.cookie_lifetime', 365); $this->addInteger('aff.cookie_lifetime', null, array('help-id' => '#Affiliate_Options')) ->setLabel(___("Affiliate Cookie Lifetime\n" . "days to store cookies about referred affiliate")) ->addRule('regex', ___('Please specify number less then 9999'), '/^[0-9]{0,4}$/'); $this->addInteger('aff.commission_days') ->setLabel(___("User-Affiliate Relation Lifetime\n" . "how long (in days) calculate commission for referred affiliate (default: 0 - forever)")); $this->setDefault('aff.commission_days', 0); $fs = $this->addFieldset() ->setLabel(___('Payout')) ->setId('payout'); $url = $this->getDi()->url('aff/admin-payout'); $fs->addHtml(null, array('class' => 'no-label')) ->setHtml(___('aMember generate payout reports automatically according your settings below. ' . 'Then you can use these reports to make real payout. You can find list of payout reports %shere%s. ' . 'User without defined valid payout method will not be included to payout report until he fill payout ' . 'method in member area.', '', '')); $el = $fs->addMagicSelect('aff.payout_methods', array( 'multiple' => 'multiple'), array('help-id' => '#Accepted_Payout_methods')) ->setLabel(___('Accepted Payout Methods')) ->loadOptions(Am_Aff_PayoutMethod::getAvailableOptions()); $el = $fs->addSelect('aff.payout_day', null, array('help-id' => '#Affiliate_Payout_Options')) ->setLabel(___("Affiliates Payout Day\n" . "choose a day of month when payout is generated")); for ($i = 1; $i <= 28; $i++) $el->addOption(___("%d-th day", $i), $i . 'd'); $wd = Am_Di::getInstance()->locale->getWeekdayNames(); for ($i = 0; $i < 7; $i++) { $el->addOption(___('Every %s', $wd[$i]), $i . 'w'); } for ($i = 0; $i < 7; $i++) { $el->addOption(___('Bi-Weekly (on %s)', $wd[$i]), $i . 'W'); } $fs->addElement('email_link', 'aff.new_payouts') ->setLabel(___('New Affiliate Payout to Admin')); $fs->addInteger('aff.payout_min', array('placeholder' => ___('Unlimited')), array('help-id' => '#Affiliate_Payout_Options')) ->setLabel(___("Minimum Payout\n" . 'minimal commission amount earned by affiliate to include it to payout report')); $fs->addInteger('aff.payout_delay_days', null, array('help-id' => '#Affiliate_Payout_Options')) ->setLabel(___("Delay Payout (days)\n" . 'number of days that should go through before commision is included to payout report')); $this->setDefault('aff.payout_delay_days', 30); $fs->addElement('email_checkbox', 'aff.notify_payout_empty') ->setLabel(___("Empty Payout Method Notification to User\n" . "send email to user in case he has commission but did not define payout method yet.\n" . 'This email will be sent only once.')); $fs->addElement('email_checkbox', 'aff.notify_payout_paid') ->setLabel(___("Affiliate Payout Paid Notification to User\n" . "send email to user when his payout is marked as paid")); $fs = $this->addFieldset() ->setLabel(___('Commission')); $gr = $fs->addGroup('', array('id' => 'commission'), array('help-id' => '#Affiliate_Payout_Options'))->setLabel(___('Default Commission')); $gr->addStatic()->setContent('
'); if (Am_Di::getInstance()->affCommissionRuleTable->hasCustomRules()) { $gr->addStatic()->setContent( ___('Custom Commission Rules added') . ' '); } else { $rule = Am_Di::getInstance()->affCommissionRuleTable->findFirstBy(array( 'type' => AffCommissionRule::TYPE_GLOBAL, 'tier' => 0)); $gr->addStatic()->setContent(___('First Payment (calculated for first payment in each invoice)') . ' '); $first = $gr->addElement(new Am_Form_Element_AffCommissionSize('aff_comm[first]', null, 'first_payment')); $gr->addStatic()->setContent(' ' . ___('Rebill') . ' '); $second = $gr->addElement(new Am_Form_Element_AffCommissionSize('aff_comm[recurring]', null, 'recurring')); $gr->addStatic()->setContent( ' ' . ___('or') . ' '); if ($rule && !$this->isSubmitted()) { $first->getElementById('first_payment_c-0')->setValue($rule->first_payment_c); $first->getElementById('first_payment_t-0')->setValue($rule->first_payment_t); $second->getElementById('recurring_c-0')->setValue($rule->recurring_c); $second->getElementById('recurring_t-0')->setValue($rule->recurring_t); } } $gr->addStatic()->setContent( '' . ___('Edit Custom Commission Rules') . '' ); $gr->addStatic()->setContent('
'); $fs->addAdvCheckbox('aff.commission_include_tax') ->setLabel(___("Calculate Affiliate Commissions from Totals Including Tax\n" . "by default commission calculated from amounts before tax")); $fs->addElement('email_checkbox', 'aff.mail_sale_admin', null, array('help-id' => '#Setting_Up_Commission_Notification_Emails')) ->setLabel(___("E-Mail Commission to Admin")); $fs->addElement('email_checkbox', 'aff.mail_sale_user', null, array('help-id' => '#Setting_Up_Commission_Notification_Emails')) ->setLabel(___('E-Mail Commission to Affiliate')); $fs = $this->addFieldset() ->setLabel(___('Miscellaneous')); $this->addAdvCheckbox('aff.affiliate_can_view_details', null, array('help-id' => '#Affiliate_Payout_Options')) ->setLabel(___("Affiliate Can View Sales Details\n" . 'Leave this checkbox unselected to restrict affiliates from seeing their sales details')); $gr = $this->addGroup() ->setLabel(___("Allow Affiliates to redirect Referrers to any url")); $gr->addSelect('aff.custom_redirect', array('id' => 'custom_redirect')) ->loadOptions( array( Bootstrap_Aff::AFF_CUSTOM_REDIRECT_DISABLED => ___('Disabled'), Bootstrap_Aff::AFF_CUSTOM_REDIRECT_ALLOW_SOME_DENY_OTHERS => ___('Allow for some affiliates, disallow for others'), Bootstrap_Aff::AFF_CUSTOM_REDIRECT_DENY_SOME_ALLOW_OTHERS => ___('Disallow for some affiliates, allow for others'), )); $gr->addHtml()->setHtml('

'); $gr->addAdvCheckbox('aff.custom_redirect_other_domains', null, array('content' => ___('Allow redirecting to external URLs'))); $this->addScript() ->setScript(<<addHtmlEditor('aff.intro', null, array('showInPopup' => true)) ->setLabel(___("Intro Text on Affiliate Info Page")); $this->addAdvCheckbox('aff.tracking_code') ->setLabel(___("Enable Click Tracking Code\n" . 'Enable ability to track affiliate clicks on any page on your site')); $url = $this->getDi()->url('signup'); $code = htmlentities(Am_Di::getInstance()->modules->loadGet('aff')->getClickJs()); $this->addHTML('tracking_code')->setHTML(<<
{$code}
Then your affiliate can use any url of your site as affiliate link. They just need to append GET parameter ?ref=username to it eg. $url?ref=username where username is actual username of affiliate. EOT )->setLabel(___('Click Tracking Code')); $this->addScript()->setScript(<<addAdvCheckbox('aff.keywords')->setLabel(___("Enable Keywords Support\n" . 'Enable ability to track traffic sources adding keywords to url')); $this->setDefault('aff.keywords', 1); } public function beforeSaveConfig(Am_Config $before, Am_Config $after) { $arr = $after->getArray(); if (empty($arr['aff_comm'])) return; $this->rule = Am_Di::getInstance()->affCommissionRuleTable->findFirstBy(array( 'type' => AffCommissionRule::TYPE_GLOBAL, 'tier' => 0)); if (empty($this->rule)) { $this->rule = Am_Di::getInstance()->affCommissionRuleTable->createRecord(); $this->rule->type = AffCommissionRule::TYPE_GLOBAL; $this->rule->tier = 0; $this->rule->comment = "Default Commmission"; } foreach ($arr['aff_comm'] as $aa) foreach ($aa as $k => $v) $this->rule->set($k, $v); unset($arr['aff_comm']); $after->setArray($arr); } public function afterSaveConfig(Am_Config $before, Am_Config $after) { if (!empty($this->rule)) $this->rule->save(); } } PK)\зyylibrary/Reports.phpnu[title = ___('Affiliate Clicks'); $this->description = ___('number of affiliate program clicks'); parent::__construct(); } public function getPointField() { return 'cl.time'; } public function getQuery() { $q = new Am_Query(new AffClickTable, 'cl'); $q->clearFields(); $q->addField('COUNT(DISTINCT cl.remote_addr) AS clicks'); $q->addField('COUNT(cl.log_id) AS clicks_all'); if ($this->aff_id) { $q->addWhere("aff_id = ?d", $this->aff_id); } return $q; } function getLines() { return array( new Am_Report_Line("clicks", ___('Unique Clicks')), new Am_Report_Line("clicks_all", ___('All Clicks')), ); } public function setAffId($aff_id) { $this->aff_id = (int)$aff_id; } } class Am_Report_AffStats extends Am_Report_Date { protected $aff_id; public function __construct() { $this->title = ___('Affiliate Sales'); $this->description = ___('affiliate program commissions'); } public function getPointField() { return 'cl.date'; } public function getQuery() { $q = new Am_Query(new AffCommissionTable, 'cl'); $q->clearFields(); $q->addField("SUM(IF(cl.record_type='commission', cl.amount, -cl.amount)) AS commission"); if ($this->aff_id) $q->addWhere("aff_id = ?d", $this->aff_id); return $q; } function getLines() { return array( new Am_Report_Line("commission", ___('Commission'), null, array('Am_Currency', 'render')), ); } public function setAffId($aff_id) { $this->aff_id = (int)$aff_id; } } class Am_Report_AffSales extends Am_Report_Date { protected $aff_id; public function __construct() { $this->title = ___('Affiliate Sales Number'); $this->description = ___('number of sales by affiliate'); } public function getPointField() { return 'cl.date'; } public function getQuery() { $q = new Am_Query(new AffCommissionTable, 'cl'); $q->clearFields(); $q->addField("COUNT(DISTINCT invoice_payment_id) AS sales"); if ($this->aff_id) $q->addWhere("aff_id = ?d and record_type='commission'", $this->aff_id); return $q; } function getLines() { return array( new Am_Report_Line("sales", ___('Sales')), ); } public function setAffId($aff_id) { $this->aff_id = (int)$aff_id; } } class Am_Report_AffUserPayout extends Am_Report_Abstract { const PERIOD_EXACT = 'exact'; public function __construct() { $this->title = ___('Affiliate Payout Amount by User'); } public function _initConfigForm(Am_Form $form) { parent::_initConfigForm($form); $period = $form->addSelect('period')->setLabel(___('Period')) ->loadOptions( array_merge($this->getDi()->interval->getOptions(), array(self::PERIOD_EXACT=> ___('Exact')))); $intervals = array(); foreach ($this->getDi()->interval->getIntervals() as $k => $v) { list($b, $e) = $v; $b = amDate($b); $e = amDate($e); $intervals[$k] = ($b == $e) ? $b : sprintf('%s—%s', $b, $e); } $period->setAttribute('data-intervals', json_encode($intervals)); $period_exact = self::PERIOD_EXACT; $script = <<').html(str)); jQuery(this).closest('.am-form').find('input[name=start], input[name=stop]'). closest('div.row'). toggle(jQuery(this).val() == '{$period_exact}'); }).change(); }) CUT; $form->addScript()->setScript($script); $start = $form->addDate('start')->setLabel(___('Start')); $start->addRule('required'); $stop = $form->addDate('stop')->setLabel(___('End')); $stop->addRule('required'); $form->addRule('callback', 'Start Date cannot be later than the End Date', array($this, 'checkStopDate')); $min = $form->addGroup() ->setLabel(___("Minimum Payout\n" . "include to report only affiliates with payout in qiven period more or equal to")); $min->setSeparator(' '); $min->addText('min', array('size'=>5, 'placeholder'=>'0.00')); $min->addStatic() ->setContent((string)Am_Currency::getDefault()); } protected function getFormDefaults() { return array( 'start' => sqlDate('-1 month'), 'stop' => sqlDate('now'), ); } public function checkStopDate($val) { $res = $val['stop']>$val['start']; if (!$res) { $elements = $this->getForm()->getElementsByName('start'); $elements[0]->setError('Start Date cannot be later than the End Date'); } return $res; } protected function getStartStop(array $values) { switch ($values['period']) { case self::PERIOD_EXACT : return array($values['start'], $values['stop']); default : return $this->getDi()->interval->getStartStop($values['period']); } } protected function runQuery() { $q = new Am_Query(new AffPayoutDetailTable, 'pd'); $q->leftJoin('?_aff_payout', 'ap', 'pd.payout_id=ap.payout_id'); $q->clearFields(); $q->addWhere('pd.is_paid=1'); $q->addField("SUM(pd.amount) AS amount"); $q->addField('pd.aff_id', self::POINT_FLD); $q->addWhere("ap.date BETWEEN ? AND ?", $this->start, $this->stop); $q->groupBy('aff_id'); $q->addHaving('amount>?', (float)$this->min); $this->stmt = $q->query(); } protected function processConfigForm(array $values) { list($start, $stop) = $this->getStartStop($values); $this->min = $values['min']; $this->setInterval($start, $stop); $op = $this->getDi()->db->selectCol(<<start, $this->stop); $quant = new Am_Report_Quant_Map($op); $this->setQuantity($quant); } public function setInterval($start, $stop) { $this->start = date('Y-m-d 00:00:00', strtotime($start)); $this->stop = date('Y-m-d 23:59:59', strtotime($stop)); return $this; } function getLines() { return array( new Am_Report_Line("amount", ___('Payout'), null, array('Am_Currency', 'render')) ); } public function getOutput(Am_Report_Result $result) { return array(new Am_Report_Table($result)); } }PK)\Y|$  email-templates.xmlnu[ aff.admin_registration_mail 2 en text %site_title%: *** New Affiliate Signup Affiliate details: Username: %affiliate.login% Email: %affiliate.email% Name: %affiliate.name_f% %affiliate.name_l% aff.registration_mail 3 en text %site_title%: Affiliate Program Registration Thank you for registration on %site_title% affiliate program! Your User ID: %affiliate.login% Your Password: %password% Log-on to your affiliate pages at: %root_url%/aff/member aff.mail_sale_admin 2 en text %site_title%: Affiliate Commission New sale has been made with using of affiliate link. You may find sale details below: ---- Affilate: %affiliate.user_id% / %affiliate.login% / %affiliate.email% %affiliate.name_f% %affiliate.name_l% / %affiliate.remote_addr% New Member: %user.user_id% / %user.login% / %user.email% %user.name_f% %user.name_l% / %user.remote_addr% Payment REF: %payment.invoice_payment_id% Total: %payment.amount% Product ordered: %product.title% Commission paid: %commission% aff.mail_sale_user 3 en text %site_title%: Affiliate Sale New sale has been made by your affiliate link and commission credited to your balance. You may find sale details below: ---- Payment REF: %payment.invoice_payment_id% Total: %amount% Product ordered: %product.title% Your commission: %commission% aff.new_payouts 2 en text %site_title%: Affiliate Payout ToDo New payouts were generated for you affiliates. Please visit %url% to pay earnings. aff.notify_payout_empty 3 en text %site_title%: Your Affiliate Payout Method is not defined yet You did not set up payout method in our affiliate programm. Your commissions will not be included to payout until you set up it. Please Log-on to your affiliate pages and set up it: %root_url%/aff/member/payout-info aff.notify_payout_paid 3 en text %site_title%: Affiliate Payout We issue payout for your affiliate account on our site. All new commissions issued until %payout.thresehold_date|date% is included to this payout. Payout Amount: %payout_detail.amount|currency% Payout Method: %payout_method_title% aff.manually_approve 3 en text %site_title%: Your affiliate signup is pending Thank you for subscribing! We review all affiliates manually, so your status is pending. You will receive email when your account will be approved. Thank you for your patience. aff.manually_approve_admin 2 en text %site_title%: Your approval required New affiliate signup completed and is awaiting your approval. Please log into aMember CP %root_url%/admin/ and then click the following link: %root_url%/admin-users?_u_a=edit&_u_id=%affiliate.user_id% Affiliate details: Username: %affiliate.login% Email: %affiliate.email% Name: %affiliate.name_f% %user.name_l% PK)\E[1 Bootstrap.phpnu[getReturn() * use $event->setReturn() */ const AFF_COMMISSION_CALCULATE = 'affCommissionCalculate'; /** * Event: Find affiliate for invoice * use $event->getReturn() to get caculated aff_id * use $event->setReturn() to set aff_id * @param Invoice $invoice * @param InvoicePayment|null $payment null for free trial! */ const AFF_FIND_AFFILIATE = 'affFindAffiliate'; const AFF_BIND_AFFILIATE = 'affBindAffiliate'; /** * Event: called to retrieve available payout methods * * @see Am_Event::addReturn() */ const AFF_GET_PAYOUT_OPTIONS = 'affGetPayoutOptions'; /** Cookie name set for user visited affiliate link */ const COOKIE_NAME = 'amember_aff_id'; const ADMIN_PERM_ID = 'affiliates'; const AFF_CUSTOM_REDIRECT_DISABLED = 0; const AFF_CUSTOM_REDIRECT_ALLOW_SOME_DENY_OTHERS = 1; const AFF_CUSTOM_REDIRECT_DENY_SOME_ALLOW_OTHERS = 2; const STORE_PREFIX = 'aff_signup_state-'; const KEYWORD_MAX_LEN = 255; protected $last_aff_id; static function activate($id, $pluginType) { parent::activate($id, $pluginType); self::setUpAffFormIfNotExist(Am_Di::getInstance()->db); } function init() { parent::init(); $this->getDi()->userTable->customFields()->addCallback(array('Am_Aff_PayoutMethod', 'static_addFields')); $this->getDi()->uploadTable->defineUsage('affiliate', 'aff_banner', 'upload_id', UploadTable::STORE_FIELD, "Affiliate Marketing Material [%title%, %desc%]", '/aff/admin-banners/p/downloads/index'); $this->getDi()->uploadTable->defineUsage('banners', 'aff_banner', 'upload_id', UploadTable::STORE_FIELD, "Affiliate Banner [%title%, %desc%]", '/aff/admin-banners/p/banners/index'); $this->getDi()->uploadTable->defineUsage('banners', 'aff_banner', 'upload_big_id', UploadTable::STORE_FIELD, "Affiliate Banner [%title%, %desc%]", '/aff/admin-banners/p/banners/index'); } function _renderInvoiceCommissions(Am_View $view) { return $this->renderInvoiceCommissions($view->invoice, $view); } function renderInvoiceCommissions(Invoice $invoice, Am_View $view) { $query = new Am_Query($this->getDi()->affCommissionTable); $query->leftJoin('?_invoice', 'i', 'i.invoice_id=t.invoice_id') ->leftJoin('?_user', 'a', 't.aff_id=a.user_id') ->leftJoin('?_product', 'p', 't.product_id=p.product_id') ->addField('TRIM(REPLACE(CONCAT(a.login, \' (\', a.name_f, \' \', a.name_l,\') #\', a.user_id), \'( )\', \'\'))', 'aff_name') ->addField('p.title', 'product_title') ->addWhere('t.invoice_id=?', $invoice->pk()) ->leftJoin('?_aff_payout_detail', 'apd', 't.payout_detail_id=apd.payout_detail_id') ->leftJoin('?_aff_payout', 'ap', 'ap.payout_id=apd.payout_id') ->addField('ap.date', 'payout_date') ->addField('ap.payout_id') ->addField('apd.is_paid') ->setOrder('commission_id', 'desc'); $items = $query->selectAllRecords(); $view->comm_items = $items; $view->invoice = $invoice; $view->has_tiers = $this->getDi()->affCommissionRuleTable->getMaxTier(); $view->aff = $this->getAffiliate($invoice); return $view->render('blocks/admin-user-invoice-details.phtml'); } function sendNotApprovedEmail(User $user) { if($et = Am_Mail_Template::load('aff.manually_approve', $user->lang)) { $et->setAffiliate($user); $et->send($user); } if($et = Am_Mail_Template::load('aff.manually_approve_admin')) { $et->setAffiliate($user); $et->send(Am_Mail_Template::TO_ADMIN); } } function renderAlert() { if ($user_id = $this->getDi()->auth->getUserId()) { $user = $this->getDi()->auth->getUser(); if ($user->is_affiliate > 0 && !in_array($user->aff_payout_type, $this->getConfig('payout_methods', array()))) { return '
' . ___('Please %sdefine payout method%s to get commission in our affiliate program.', '', '') . '
'; } } } function onLoadAdminDashboardWidgets(Am_Event $event) { $event->addReturn(new Am_Widget('aff-top-affiliate', ___('Top Affiliate'), array($this, 'renderWidgetTopAffiliate'), Am_Widget::TARGET_ANY, array($this, 'createWidgetTopAffiliateConfigForm'), self::ADMIN_PERM_ID)); } public function renderWidgetTopAffiliate(Am_View $view, $config = null) { $intervals = is_null($config) ? array(Am_Interval::PERIOD_THIS_WEEK_FROM_SUN) : (array)$config['interval']; $out = ''; foreach ($intervals as $interval) { list($start, $stop) = $this->getDi()->interval->getStartStop($interval); $view->start = $start; $view->stop = $stop; $view->reportTitle = $this->getDi()->interval->getTitle($interval); $q = new Am_Query($this->getDi()->userTable); $q->addWhere('t.is_affiliate>?', 0); $q->addField("CONCAT(t.name_f, ' ', t.name_l)", 'name'); $q->leftJoin('?_aff_commission', 'c', 'c.aff_id=t.user_id'); $q->addWhere('c.tier=0'); $q->addField("SUM(IF(record_type='commission', amount, -amount))", 'comm'); $q->addHaving('comm>?', 0); $q->addOrder('comm', true); $q->addWhere("c.date >= ?", $start); $q->addWhere("c.date <= ?", $stop); if (isset($config['is_first']) && $config['is_first']) { $q->addWhere("c.is_first=?", 1); } if (isset($config['pids']) && $config['pids']) { $pids = $this->getDi()->productTable->extractProductIds($config['pids']); $pids[] = -1; $q->addWhere("c.product_id IN (?a)", $pids); } $num = @$config['num'] ?: 10; $view->num = $num; $view->affiliates = $q->selectPageRecords(0, $num); $out .= $view->render('admin/aff/widget/top-affiliate.phtml'); } return $out; } function createWidgetTopAffiliateConfigForm() { $form = new Am_Form_Admin(); $form->addSortableMagicSelect('interval', null, array('options' => $this->getDi()->interval->getOptions())) ->setLabel(___('Period')) ->setValue(array(Am_Interval::PERIOD_THIS_WEEK_FROM_SUN)); $form->addMagicSelect('pids') ->loadOptions($this->getDi()->productTable->getProductOptions()) ->setLabel(___("Products\n" . "leave it empty to include all products")); $form->addAdvCheckbox('is_first') ->setLabel(___("Consider only initial purchase\n" . "disregard subsequent recurring payments")); $form->addInteger('num', array('placeholder' => 10)) ->setLabel(___('Number of Affiliates')); return $form; } function onUserSearchConditions(Am_Event $e) { $e->addReturn(new Am_Query_User_Condition_AffWithCommission); } function onGetApiControllers(Am_Event $e) { $list = $e->getList(); $list->addController('aff-payouts', 'aff-payouts', $list->gridMethods, 'Affiliate Payouts', 'aff'); $list->addController('aff-payout-details', 'aff-payout-details', $list->gridMethods, 'Affiliate Payout Details', 'aff'); } function onClearItems(Am_Event $event) { $event->addReturn(array( 'method' => array($this->getDi()->affClickTable, 'clearOld'), 'title' => 'Affiliate Clicks', 'desc' => '' ), 'aff_click'); } function onValidateCoupon(Am_Event $e) { $batch = $e->getCouponBatch(); $coupon = $e->getCoupon(); $user = $e->getUser(); if ($user && $batch->aff_id && $batch->aff_id == $user->pk()) { $e->addReturn(___("You can't use your affiliate coupon code")); } if ($user && $coupon->aff_id && $coupon->aff_id == $user->pk()) { $e->addReturn(___("You can't use your affiliate coupon code")); } } function onInvoiceAfterDelete(Am_Event $e) { $this->getDi()->affCommissionTable->deleteByInvoiceId($e->getInvoice()->pk()); } function onInvoiceBeforeInsert(Am_Event $e) { $invoice = $e->getInvoice(); $aff_id = !empty($invoice->aff_id) ? $invoice->aff_id : ($invoice->getUser() ? $invoice->getUser()->aff_id : null); if(!empty($aff_id)) $invoice->keyword_id = $this->findKeywordId($aff_id); } function onAdminWarnings(Am_Event $event) { $cnt = $this->getConfig('payout_methods'); if (empty($cnt)) $event->addReturn(___('Please %senable at least one payout method%s since you use affiliate module', sprintf('', $this->getDi()->url('admin-setup/aff')), '')); } function onSetupEmailTemplateTypes(Am_Event $event) { $event->addReturn(array( 'id' => 'aff.mail_sale_user', 'title' => 'Aff Mail Sale User', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array( 'user', 'affiliate', 'amount' => ___('Total Amount of Payment'), 'tier' => ___('Affiliate Tier')), ), 'aff.mail_sale_user'); $event->addReturn(array( 'id' => 'aff.mail_sale_admin', 'title' => 'Aff Mail Sale Admin', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'isAdmin' => true, 'vars' => array( 'user', 'affiliate', 'amount' => ___('Total Amount of Payment'), 'tier' => ___('Affiliate Tier')), ), 'aff.mail_sale_admin'); $event->addReturn(array( 'id' => 'aff.notify_payout_empty', 'title' => 'Empty Payout Method Notification to User', 'mailPeriodic' => Am_Mail::USER_REQUESTED, 'vars' => array( 'affiliate' )), 'aff.notify_payout_empty'); $event->addReturn(array( 'id' => 'aff.notify_payout_paid', 'title' => 'Affiliate Payout Paid Notification to User', 'mailPeriodic' => Am_Mail::REGULAR, 'vars' => array( 'affiliate', 'payout.threshold_date' => ___('Threshold Date'), 'payout_detail.amount' => ___('Amount'), 'payout_method_title' => ___('Payout Method Title') )), 'aff.notify_payout_paid'); $event->addReturn(array( 'id' => 'aff.admin_registration_mail', 'title' => 'Affiliate Registration Notification to Admin', 'mailPeriodic' => Am_Mail::REGULAR, 'isAdmin' => true, 'vars' => array('affiliate')), 'aff.admin_registration_mail'); } function onUserMerge(Am_Event $event) { $target = $event->getTarget(); $source = $event->getSource(); $this->getDi()->db->query('UPDATE ?_aff_click SET aff_id=? WHERE aff_id=?', $target->pk(), $source->pk()); $this->getDi()->db->query('UPDATE ?_aff_commission SET aff_id=? WHERE aff_id=?', $target->pk(), $source->pk()); $this->getDi()->db->query('UPDATE ?_aff_lead SET aff_id=? WHERE aff_id=?', $target->pk(), $source->pk()); $this->getDi()->db->query('UPDATE ?_aff_payout_detail SET aff_id=? WHERE aff_id=?', $target->pk(), $source->pk()); $this->getDi()->db->query('UPDATE ?_user SET aff_id=? WHERE aff_id=?', $target->pk(), $source->pk()); } function onGetMemberLinks(Am_Event $e) { $u = $e->getUser(); if (!$u->is_affiliate && !$this->getDi()->config->get('aff.signup_type')) $e->addReturn(___('Advertise our website to your friends and earn money'), $this->getDi()->url('aff/aff/enable-aff')); } function onGetUploadPrefixList(Am_Event $event) { $event->addReturn(array( Am_Upload_Acl::IDENTITY_TYPE_ADMIN => array( self::ADMIN_PERM_ID => Am_Upload_Acl::ACCESS_ALL ), Am_Upload_Acl::IDENTITY_TYPE_USER => Am_Upload_Acl::ACCESS_READ, Am_Upload_Acl::IDENTITY_TYPE_ANONYMOUS => Am_Upload_Acl::ACCESS_READ ), "banners"); $event->addReturn(array( Am_Upload_Acl::IDENTITY_TYPE_ADMIN => array( self::ADMIN_PERM_ID => Am_Upload_Acl::ACCESS_ALL ), Am_Upload_Acl::IDENTITY_TYPE_AFFILIATE => Am_Upload_Acl::ACCESS_READ ), "affiliate"); } function onGetPermissionsList(Am_Event $event) { $event->addReturn("Can see affiliate info/make payouts", self::ADMIN_PERM_ID); } function onUserMenu(Am_Event $event) { if (!$event->getUser()->is_affiliate) return; $event->getMenu()->addPage( array( 'id' => 'aff', 'controller' => 'aff', 'module' => 'aff', 'label' => ___('Affiliate Info'), 'order' => 300, 'pages' => array_merge(array( array( 'id' => 'aff-links', 'controller' => 'aff', 'module' => 'aff', 'label' => ___('Banners and Links'), ), array( 'id' => 'aff-stats', 'controller' => 'member', 'module' => 'aff', 'action' => 'stats', 'label' => ___('Statistics'), ), array( 'id' => 'aff-payout-info', 'controller' => 'member', 'module' => 'aff', 'action' => 'payout-info', 'label' => ___('Payout Method'), ), array( 'id' => 'aff-payout', 'controller' => 'member', 'module' => 'aff', 'action' => 'payout', 'label' => ___('Payouts'), ), ), $this->getConfig('keywords') ? array( array( 'id' => 'aff-keywords', 'controller' => 'member', 'module' => 'aff', 'action' => 'keywords', 'label' => ___('Keywords'), ), ) : array()) ) ); } function onAdminMenu(Am_Event $event) { $menu = $event->getMenu(); $menu->addPage(array( 'id' => 'affiliates', 'uri' => 'javascript:;', 'label' => ___('Affiliates'), 'resource' => self::ADMIN_PERM_ID, 'pages' => array_merge(array( array( 'id' => 'affiliates-commission-rules', 'controller' => 'admin-commission-rule', 'module' => 'aff', 'label' => ___('Commission Rules'), 'resource' => self::ADMIN_PERM_ID, ), array( 'id' => 'affiliates-payout', 'controller' => 'admin-payout', 'module' => 'aff', 'label' => ___("Review/Pay Commissions"), 'resource' => self::ADMIN_PERM_ID, ), array( 'id' => 'affiliates-commission', 'controller' => 'admin-commission', 'module' => 'aff', 'label' => ___('Clicks/Sales Statistics'), 'resource' => self::ADMIN_PERM_ID, ), array( 'id' => 'affiliates-banners', 'controller' => 'admin-banners', 'module' => 'aff', 'label' => ___('Banners and Text Links'), 'resource' => self::ADMIN_PERM_ID, ) ), !Am_Di::getInstance()->config->get('manually_approve') && (Am_Di::getInstance()->config->get('aff.signup_type') != 2) ? array() : array(array( 'id' => 'user-not-approved', 'controller' => 'admin-users', 'action' => 'not-approved', 'label' => ___('Not Approved Affiliates'), 'resource' => 'grid_u', 'privilege' => 'browse', )) ) )); } public function addPayoutInputs(HTML_QuickForm2_Container $fieldSet) { $el = $fieldSet->addSelect('aff_payout_type') ->setLabel(___('Affiliate Payout Type')) ->loadOptions(array_merge(array('' => ___('Not Selected')))); foreach (Am_Aff_PayoutMethod::getEnabled() as $method) $el->addOption($method->getTitle(), $method->getId()); $fieldSet->addScript()->setScript(' /**** show only options for selected payout method */ jQuery(function(){ jQuery("#' . $el->getId() . '").change(function() { var selected = jQuery("#' . $el->getId() . '").val(); jQuery("option", jQuery(this)).each(function(){ var option = jQuery(this).val(); if(option == selected){ jQuery("input[name^=aff_"+option+"_],textarea[name^=aff_"+option+"_],select[name^=aff_"+option+"_]").closest(".row").show(); }else{ jQuery("input[name^=aff_"+option+"_],textarea[name^=aff_"+option+"_],select[name^=aff_"+option+"_]").closest(".row").hide(); } }); }).change(); }); /**** end of payout method options */ '); foreach ($this->getDi()->userTable->customFields()->getAll() as $f) if (strpos($f->name, 'aff_') === 0) $f->addToQf2($fieldSet); } public function onGridCouponInitGrid(Am_Event_Grid $event) { $event->getGrid()->addField('aff_id', ___('Affiliate')) ->setRenderFunction(array($this, 'renderAffiliate')); $event->getGrid()->actionAdd(new Am_Grid_Action_LiveEdit('aff_id', ___('Click to Assign'))) ->setInitCallback('l = function(){this.autocomplete({ minLength: 2, source: amUrl("/aff/admin/autocomplete/") });}') ->getDecorator()->setInputTemplate(sprintf('', ___('Type Username or E-Mail'))); $event->getGrid()->addCallback(Am_Grid_ReadOnly::CB_RENDER_CONTENT, array($this, 'couponRenderContent')); } public function couponRenderContent(& $out) { $out = sprintf('
%s
', ___('You can assign some coupon codes to specific affiliate. ' . 'Whenever coupon is used, commission will always be credited to '. 'this affiliate. This is true even when another affiliate is permanently ' . 'tagged to the customer. For sales where the coupon is NOT used, the ' . 'original (previous) affiliate will continue receiving commissions. If the ' . 'customer has no affiliate, this affiliate will permanently be tagged to the ' . 'customer, and will receive credit for future sales.')) . $out; } public function onCouponBeforeUpdate(Am_Event $event) { $coupon = $event->getCoupon(); if (!$coupon->aff_id) $coupon->aff_id = null; if (!is_numeric($coupon->aff_id)) { $user = $this->getDi()->userTable->findFirstByLogin($coupon->aff_id); $coupon->aff_id = $user ? $user->pk() : null; } } public function renderAffiliate($rec) { $aff = $rec->aff_id ? $this->getDi()->userTable->load($rec->aff_id, false) : null; return $aff ? sprintf('%s', Am_Html::escape($aff->login)) : ''; } public function onGridCouponBatchBeforeSave(Am_Event_Grid $event) { $input = $event->getGrid()->getForm()->getValue(); if (!empty($input['_aff'])) { $aff = $this->getDi()->userTable->findFirstByLogin($input['_aff'], false); if ($aff) { $event->getGrid()->getRecord()->aff_id = $aff->pk(); } else { throw new Am_Exception_InputError("Affiliate not found, username specified: " . Am_Html::escape($input['_aff'])); } } elseif (isset($input['_aff']) && $input['_aff'] == '') { //reset affiliate $event->getGrid()->getRecord()->aff_id = null; } } function onGridCouponBatchInitForm(Am_Event $event) { /* @var $form Am_Form_Admin */ $form = $event->getGrid()->getForm(); $fieldSet = $form->getElementById('coupon-batch'); $batch = $event->getGrid()->getRecord(); $affGroup = $fieldSet->addGroup() ->setLabel(___("Affiliate\n" . "whenever coupons from this batch is used, commission will always be credited to " . "this affiliate. This is true even when another affiliate is permanently " . "tagged to the customer. For sales where the coupon is NOT used, the " . "original (previous) affiliate will continue receiving commissions. If the " . "customer has no affiliate, this affiliate will permanently be tagged to the " . "customer, and will receive credit for future sales.")); $affEl = $affGroup->addText('_aff', array('placeholder' => ___('Type Username or E-Mail'))) ->setId('aff-affiliate'); $fieldSet->addScript()->setScript(<<aff_id)) { try { $aff = $this->getDi()->userTable->load($batch->aff_id); $affEl->setValue($aff->login); $affEl->setAttribute('style', 'display:none'); $url = new Am_View_Helper_UserUrl; $affHtml = sprintf('', Am_Html::escape($url->userUrl($batch->aff_id)), $aff->name_f, $aff->name_l, $aff->email, ___('Unassign Affiliate') ); $affGroup->addStatic() ->setContent($affHtml); $affGroup->addScript()->setScript(<<getDi()->authAdmin->getUser()->hasPermission(self::ADMIN_PERM_ID)) return; $input = $event->getGrid()->getForm()->getValue(); if (!empty($input['_aff'])) { $aff = $this->getDi()->userTable->findFirstByLogin($input['_aff'], false); if ($aff) { if ($aff->pk() == $event->getGrid()->getRecord()->pk()) { throw new Am_Exception_InputError("Cannot assign affiliate to himself"); } if ($event->getGrid()->getRecord()->aff_id != $aff->pk()) { $e = new Am_Event(self::AFF_BIND_AFFILIATE, array( 'user' => $event->getGrid()->getRecord() )); $e->setReturn($aff->pk()); $this->getDi()->hook->call($e); $aff_id = $e->getReturn(); $event->getGrid()->getRecord()->aff_id = $aff_id; $event->getGrid()->getRecord()->aff_added = sqlTime('now'); $event->getGrid()->getRecord()->data()->set('aff-source', 'admin-' . $this->getDi()->authAdmin->getUserId()); } } else { throw new Am_Exception_InputError("Affiliate not found, username specified: " . Am_Html::escape($input['_aff'])); } } elseif (isset($input['_aff']) && $input['_aff'] == '') { //reset affiliate $event->getGrid()->getRecord()->aff_id = null; $event->getGrid()->getRecord()->aff_added = null; $event->getGrid()->getRecord()->data()->set('aff-source', null); } } public function onGridUserInitForm(Am_Event_Grid $event) { if (!$this->getDi()->authAdmin->getUser()->hasPermission(self::ADMIN_PERM_ID)) return; $fieldSet = $event->getGrid()->getForm()->addAdvFieldset('affiliate')->setLabel(___('Affiliate Program')); $user = $event->getGrid()->getRecord(); $user_id = $user->pk(); $affGroup = $fieldSet->addGroup() ->setLabel(___('Referred Affiliate')); $affEl = $affGroup->addText('_aff', array('placeholder' => ___('Type Username or E-Mail'))) ->setId('aff-refered-affiliate'); $fieldSet->addScript()->setScript(<<aff_id)) { try { $aff = $this->getDi()->userTable->load($user->aff_id); $affEl->setValue($aff->login); $affEl->setAttribute('style', 'display:none'); $url = new Am_View_Helper_UserUrl; $is_expired = false; if ($commissionDays = $this->getDi()->config->get('aff.commission_days')) { $signupDays = $this->getDi()->time - strtotime($user->aff_added ? $user->aff_added : $user->added); $signupDays = intval($signupDays / (3600 * 24)); // to days if ($commissionDays < $signupDays) $is_expired = true; } $affHtml = sprintf('', Am_Html::escape($url->userUrl($user->aff_id)), $aff->name_f, $aff->name_l, $aff->email, ___('Unassign Affiliate'), ($is_expired ? sprintf('
%s
', ___('affiliate <-> user relation is expired (%saccording your settings%s User-Affiliate Relation Lifetime is %d day(s)), no commissions will be added for new payments', '', '', $commissionDays)) : '') ); $affGroup->addHtml() ->setHtml($affHtml); $affGroup->addScript()->setScript(<<isLoaded() && ($source = $user->data()->get('aff-source'))) { preg_match('/^([a-z]*)(-(.*))?$/i', $source, $match); $res = ''; switch ($match[1]) { case 'ip': $res = ___('Assigned by IP %s at %s', $match[3], amDatetime($user->aff_added)); break; case 'cookie': $res = ___('Assigned by COOKIE at %s', amDatetime($user->aff_added)); break; case 'admin': $admin = $this->getDi()->adminTable->load($match[3], false); $res = ___('Assigned by Administrator %s at %s', $admin ? sprintf('%s (%s %s)', $admin->login, $admin->name_f, $admin->name_l) : '#' . $match[3], amDatetime($user->aff_added)); break; case 'coupon': $res = ___('Assigned by Coupon %s at %s', '' . $match[3] . '', amDatetime($user->aff_added)); break; case 'invoice': $invoice = $this->getDi()->invoiceTable->load($match[3], false); $res = ___('Assigned by Invoice %s at %s', $invoice ? '' . $invoice->pk() . '/' . $invoice->public_id . '' : '#' . $match[3] . '', amDatetime($user->aff_added)); break; default; $res = $source; } $fieldSet->addHtml() ->setLabel(___('Affiliate Source')) ->setHtml('
' . $res . '
'); } $fieldSet->addAdvRadio('is_affiliate') ->setLabel(___("Is Affiliate?\n" . 'customer / affiliate status')) ->loadOptions(array( '0' => ___('No'), '1' => ___('Both Affiliate and member'), '2' => ___('Only Affiliate %s(rarely used)%s', '', ''), ))->setValue($this->getConfig('signup_type') == 1 ? 1 : 0); if ($user->is_affiliate) { $link = $this->getGeneralAffLink($user); $fieldSet->addHtml() ->setHtml(sprintf('%1$s', Am_Html::escape($link))) ->setLabel(___('Affiliate Link')); } if ($cr = $this->getConfig('custom_redirect')) $fieldSet->addAdvRadio('aff_custom_redirect') ->setLabel(___('Allow Affiliate to redirect Referrers to any url')) ->loadOptions(array( '0' => $cr == self::AFF_CUSTOM_REDIRECT_ALLOW_SOME_DENY_OTHERS ? ___('No') : ___('Yes'), '1' => $cr == self::AFF_CUSTOM_REDIRECT_DENY_SOME_ALLOW_OTHERS ? ___('No') : ___('Yes') )); $this->addPayoutInputs($fieldSet); } function onUserTabs(Am_Event_UserTabs $event) { if ($event->getUserId() > 0) { $user = $this->getDi()->userTable->load($event->getUserId()); if ($user->is_affiliate > 0) { $event->getTabs()->addPage(array( 'id' => 'aff', 'uri' => '#', 'label' => ___('Affiliate Info'), 'order' => 1000, 'resource' => self::ADMIN_PERM_ID, 'pages' => array( array( 'id' => 'aff-stat', 'module' => 'aff', 'controller' => 'admin', 'action' => 'info-tab', 'params' => array( 'user_id' => $event->getUserId(), ), 'label' => ___('Statistics'), 'resource' => self::ADMIN_PERM_ID ), array( 'id' => 'aff-subaff', 'module' => 'aff', 'controller' => 'admin', 'action' => 'subaff-tab', 'params' => array( 'user_id' => $event->getUserId(), ), 'label' => ___('Sub-Affiliates'), 'resource' => self::ADMIN_PERM_ID, ), array( 'id' => 'aff-comm', 'module' => 'aff', 'controller' => 'admin', 'action' => 'comm-tab', 'params' => array( 'user_id' => $event->getUserId(), ), 'label' => ___('Commissions'), 'resource' => self::ADMIN_PERM_ID, ), array( 'id' => 'aff-payout', 'module' => 'aff', 'controller' => 'admin', 'action' => 'payout-tab', 'params' => array( 'user_id' => $event->getUserId(), ), 'label' => ___('Payouts'), 'resource' => self::ADMIN_PERM_ID, ) ) )); } } } function getAffiliate(Invoice $invoice, InvoicePayment $payment = null) { $aff_id = $invoice->aff_id; /* @var $coupon Coupon */ try { if (!$aff_id && $coupon = $invoice->getCoupon()) { // try to find affiliate by coupon $aff_id = $coupon->aff_id ? $coupon->aff_id : $coupon->getBatch()->aff_id; } } catch (Am_Exception_Db_NotFound $e) {} if (empty($aff_id)) $aff_id = $invoice->getUser()->aff_id; if ($aff_id && empty($invoice->aff_id)) // set aff_id to invoice for quick access next time $invoice->updateQuick('aff_id', $aff_id); // run event to get plugins chance choose another affiliate $event = new Am_Event(Bootstrap_Aff::AFF_FIND_AFFILIATE, array( 'invoice' => $invoice, 'payment' => $payment, )); $event->setReturn($aff_id); $this->getDi()->hook->call($event); $aff_id = $event->getReturn(); if (empty($aff_id)) return; // no affiliate id registered if ($aff_id == $invoice->getUser()->pk()) return; //strange situation $aff = $this->getDi()->userTable->load($aff_id, false); if (!$aff || !$aff->is_affiliate) return; // affiliate not found return $aff; } /** * if $_COOKIE is empty, find matches for user by IP address in aff_clicks table */ function findAffId(& $aff_source = null) { $aff_id = !empty($_COOKIE[self::COOKIE_NAME]) ? $_COOKIE[self::COOKIE_NAME] : null; $aff_source = null; //backwards compatiablity of affiliate cookies //first fragment of affiliate cookie can be user_id //or base64_encoded login $aff_info = explode('-', $aff_id); if ($aff_info[0] && !is_numeric($aff_info[0])) { $login = base64_decode($aff_info[0]); if ($user = $this->getDi()->userTable->findFirstByLogin($login)) { $aff_id = preg_replace('/^.*?-/i', $user->pk() . '-', $aff_id); $aff_source = 'cookie'; } else { $aff_id = null; } } // if (empty($aff_id)) { // $aff_id = $this->getDi()->affClickTable->findAffIdByIp($_SERVER['REMOTE_ADDR']); // $aff_source = 'ip-' . $_SERVER['REMOTE_ADDR']; // } return $aff_id; } function findKeywordId($aff_id, $keyword=null) { if(defined('AM_ADMIN') && AM_ADMIN) return null; if(isset($this->cached_keyword_id)) return $this->cached_keyword_id; if(!($aff = $this->getDi()->userTable->load($aff_id, false))) return; if(is_null($keyword)) { $cookie_name = sprintf("%s-%s", self::COOKIE_NAME, md5($aff->login)); $keyword = !empty($_COOKIE[$cookie_name]) ? base64_decode($_COOKIE[$cookie_name]) : null; } if(!$keyword) return null; $id = $this->getDi()->db->selectCell("" . "SELECT * " . "FROM " . "?_aff_keyword " . "WHERE aff_id=? AND `value`=?" . "", $aff_id, $keyword); if(!$id) { try{ $this->getDi()->db->query("" . "INSERT INTO ?_aff_keyword " . "(aff_id, `value`) " . "VALUES " . "(?, ?)" . "", $aff_id, $keyword); $id = $this->getDi()->db->selectCell("SELECT LAST_INSERT_ID()"); } catch(Exception $e) { return null; } } $this->cached_keyword_id = $id; return $this->cached_keyword_id; } /** * @param Am_Event_UserBeforeInsert $event */ function onUserBeforeInsert(Am_Event_UserBeforeInsert $event) { // skip this code if running from aMember CP if (defined('AM_ADMIN') && AM_ADMIN) return; $aff_id = $this->findAffId($aff_source); $e = new Am_Event(self::AFF_BIND_AFFILIATE, array( 'user' => $event->getUser() )); $e->setReturn($aff_id); $this->getDi()->hook->call($e); $aff_id = $e->getReturn(); // remember for usage in onUserAfterInsert $this->last_aff_id = $aff_id; if ($aff_id > 0) { $event->getUser()->aff_id = intval($aff_id); $event->getUser()->aff_added = sqlTime('now'); if ($aff_source) $event->getUser()->data()->set('aff-source', $aff_source); } if (empty($event->getUser()->is_affiliate)) $event->getUser()->is_affiliate = $this->getDi()->config->get('aff.signup_type') == 1 ? 1 : 0; } function onUserAfterInsert(Am_Event_UserAfterInsert $event) { // skip this code if running from aMember CP @see $this->onUserBeforeInsert() if (preg_match('/^(\d+)-(\d+)-(-?\d+)$/', $this->last_aff_id, $regs)) { $this->getDi()->affLeadTable->log($regs[1], $regs[2], $event->getUser()->pk(), $this->decodeClickId($regs[3])); } } function onUserAfterDelete(Am_Event_UserAfterDelete $event) { foreach (array('?_aff_click', '?_aff_commission', '?_aff_lead') as $table) { $this->getDi()->db->query("DELETE FROM $table WHERE aff_id=?", $event->getUser()->pk()); } $this->getDi()->db->query("UPDATE ?_user SET aff_id = NULL WHERE aff_id =?", $event->getUser()->pk()); } function onUserBeforeUpdate(Am_Event $e) { if (!$e->getUser()->aff_payout_type) $e->getUser()->aff_payout_type = null; } function onUserAfterUpdate(Am_Event_UserAfterUpdate $e) { if ($e->getUser()->is_approved && !$e->getOldUser()->is_approved && $e->getUser()->is_affiliate) $this->sendAffRegistrationEmail($e->getUser()); } /** * Handle free signups */ function onInvoiceStarted(Am_Event_InvoiceStarted $event) { $invoice = $event->getInvoice(); $isFirst = !$this->getDi()->db->selectCell("SELECT COUNT(*) FROM ?_invoice WHERE user_id=? AND invoice_id<>? AND tm_started IS NOT NULL", $invoice->user_id, $invoice->pk()); if (($invoice->first_total == 0) && ($invoice->second_total == 0) && $isFirst) { $this->getDi()->affCommissionRuleTable->processPayment($invoice); } } /** * Handle payments */ function onPaymentAfterInsert(Am_Event_PaymentAfterInsert $event) { $this->getDi()->affCommissionRuleTable->processPayment($event->getInvoice(), $event->getPayment()); } /** * Handle refunds */ function onRefundAfterInsert(Am_Event $event) { $this->getDi()->affCommissionRuleTable->processRefund($event->getInvoice(), $event->getRefund()); } function onAffCommissionAfterInsert(Am_Event $event) { /* @var $commission AffCommission */ $commission = $event->getCommission(); if ($commission->record_type == AffCommission::VOID) return; // void if (empty($commission->invoice_item_id)) return; /* @var $invoice_item InvoiceItem */ $invoice_item = $this->getDi()->invoiceItemTable->load($commission->invoice_item_id); $amount = $commission->is_first ? $invoice_item->first_total : $invoice_item->second_total; if ($this->getConfig('mail_sale_admin')) { if ($et = Am_Mail_Template::load('aff.mail_sale_admin')) $et->setPayment($commission->getPayment()) ->setInvoice($invoice = $commission->getInvoice()) ->setAffiliate($commission->getAff()) ->setUser($invoice->getUser()) ->setCommission($commission->amount) ->setTier($commission->tier + 1) ->setProduct($this->getDi()->productTable->load($commission->product_id, false)) ->setInvoiceItem($invoice_item) ->setAmount($amount) ->sendAdmin(); } if ($this->getConfig('mail_sale_user')) { if ($et = Am_Mail_Template::load('aff.mail_sale_user')) $et->setPayment($commission->getPayment()) ->setInvoice($invoice = $commission->getInvoice()) ->setAffiliate($commission->getAff()) ->setUser($invoice->getUser()) ->setCommission($commission->amount) ->setTier($commission->tier + 1) ->setProduct($this->getDi()->productTable->load($commission->product_id, false)) ->setInvoiceItem($invoice_item) ->setAmount($amount) ->send($commission->getAff()); } if ($this->getConfig('notify_payout_empty')) { $aff = $event->getAff(); if (in_array($aff->aff_payout_type, $this->getConfig('payout_methods', array())) || $aff->data()->get('notify_payout_empty_sent')) { return; } $aff->data()->set('notify_payout_empty_sent', 1); $aff->save(); $et = Am_Mail_Template::load('aff.notify_payout_empty', $aff->lang); $et->setAffiliate($aff) ->send($aff); } } function onSignupStateSave(Am_Event $e) { if (isset($_COOKIE[self::COOKIE_NAME])) { $code = $e->getCode(); $this->getDi()->store->set(self::STORE_PREFIX . $code, $_COOKIE[self::COOKIE_NAME], '+12 hours'); } } function onSignupStateLoad(Am_Event $e) { $code = $e->getCode(); if ($cookie = $this->getDi()->store->get(self::STORE_PREFIX . $code)) { $tm = $this->getDi()->time + $this->getDi()->config->get('aff.cookie_lifetime', 30) * 3600 * 24; Am_Cookie::set(self::COOKIE_NAME, $cookie, $tm, '/', $_SERVER['HTTP_HOST']); $_COOKIE[self::COOKIE_NAME] = $cookie; } } // utility functions function setCookie(User $aff, /* AffBanner */ $banner = null, $aff_click_id = null) { $tm = $this->getDi()->time + $this->getDi()->config->get('aff.cookie_lifetime', 30) * 3600 * 24; $val = base64_encode($aff->login); $val .= '-' . ($banner ? $banner->pk() : "0"); if ($aff_click_id) $val .= '-' . $this->encodeClickId($aff_click_id); Am_Cookie::set(self::COOKIE_NAME, $val, $tm, '/', $_SERVER['HTTP_HOST']); } function setKeywordCookie(User $aff, $keyword=null) { $tm = $this->getDi()->time + $this->getDi()->config->get('aff.cookie_lifetime', 30) * 3600 * 24; if(!is_null($keyword)) Am_Cookie::set(sprintf("%s-%s", self::COOKIE_NAME, md5($aff->login)), base64_encode($keyword), $tm, '/', $_SERVER['HTTP_HOST']); } function encodeClickId($id) { // we use only part of key to don't give attacker enough results to guess key $key = crc32(substr($this->getDi()->security->siteKey(), 1, 9)) % 100000; return $id + $key; } function decodeClickId($id) { $key = crc32(substr($this->getDi()->security->siteKey(), 1, 9)) % 100000; return $id - $key; } /** * run payouts when scheduled */ function onDaily(Am_Event $event) { $delay = $this->getConfig('payout_day'); if (!$delay) return; list($count, $unit) = preg_split('/(\D)/', $delay, 2, PREG_SPLIT_DELIM_CAPTURE); switch ($unit) { case 'd': if ($count != (int) date('d', amstrtotime($event->getDatetime()))) return; break; case 'w': $w = date('w', amstrtotime($event->getDatetime())); if ($count != $w) return; break; case 'W' : $w = date('w', amstrtotime($event->getDatetime())); if ($count != $w) return; $wn = date('W', amstrtotime($event->getDatetime())); if ($wn % 2) return; break; default : throw new Am_Exception_InternalError(sprintf('Unknown unit [%s] in %s::%s', $unit, __CLASS__, __METHOD__)); } $this->getDi()->affCommissionTable->runPayout(sqlDate($event->getDatetime())); } function onBuildDemo(Am_Event $event) { $referrers = array( 'http://example.com/some/url.html', 'http://example.com/some/other/url.html', 'http://example.com/page/offer.html', 'http://example.com/very/very/long/referrer/url.html', 'http://example.com/referrer.html' ); static $banners = null; if (is_null($banners)) { $banners = $this->getDi()->affBannerTable->findBy(); array_push($banners, null); } $user = $event->getUser(); $user->is_affiliate = 1; $user->aff_payout_type = 'check'; if (rand(0, 10) < 4) { $aff_id = $this->getDi()->db->selectCell("SELECT `id` FROM ?_data WHERE `table`='user' AND `key`='demo-id' AND `value`=? LIMIT ?d, 1", $event->getDemoId(), rand(0, $event->getUsersCreated())); if ($aff_id) { $aff = $this->getDi()->userTable->load($aff_id); $banner = $banners[array_rand($banners)]; $banner_id = $banner ? $banner->pk() : null; $user->aff_id = $aff_id; $user->aff_added = $user->added; $user->data()->set('aff-source', 'cookie'); $server = $_SERVER; $_SERVER['REMOTE_ADDR'] = $user->remote_addr; $_SERVER['HTTP_REFERER'] = $referrers[array_rand($referrers)]; $this->getDi()->setService('time', amstrtotime($user->added) - rand(5 * 60, 3600)); $aff_click_id = $this->getDi()->affClickTable->log($aff, $banner); $this->getDi()->setService('time', amstrtotime($user->added)); $this->getDi()->affLeadTable->log($aff_id, $banner_id, $user->pk(), $aff_click_id); $_SERVER = $server; $this->getDi()->setService('time', time()); } } } function onSavedFormTypes(Am_Event $event) { $event->getTable()->addTypeDef(array( 'type' => 'aff', 'class' => 'Am_Form_Signup_Aff', 'title' => ___('Affiliate Signup Form'), 'defaultTitle' => ___('Affiliate Signup Form'), 'defaultComment' => '', 'generateCode' => false, 'urlTemplate' => 'aff/signup', 'isSingle' => true, 'isSignup' => true, 'noDelete' => true, )); } function onLoadReports() { include_once AM_APPLICATION_PATH . '/aff/library/Reports.php'; } function onLoadBricks() { include_once AM_APPLICATION_PATH . '/aff/library/Am/Form/Brick.php'; } function sendAffRegistrationEmail(User $user) { if ($this->getConfig('registration_mail') && ($et = Am_Mail_Template::load('aff.registration_mail', $user->lang))) { $et->setAffiliate($user); $et->setUser($user); //backwards $et->password = $user->getPlaintextPass(); $et->send($user); } } function sendAdminRegistrationEmail(User $user) { if ($this->getConfig('admin_registration_mail') && ($et = Am_Mail_Template::load('aff.admin_registration_mail', $user->lang))) { $et->setAffiliate($user); $et->password = $user->getPlaintextPass(); $et->sendAdmin(); } } function onDbUpgrade(Am_Event $e) { if (version_compare($e->getVersion(), '4.2.6') < 0) { echo "Convert commission rule type..."; if (ob_get_level ()) ob_end_flush(); $this->getDi()->db->query("UPDATE ?_aff_commission_rule SET type=?, tier=? WHERE type=?", 'global', 0, 'global-1'); $this->getDi()->db->query("UPDATE ?_aff_commission_rule SET type=?, tier=? WHERE type=?", 'global', 1, 'global-2'); echo "Done
\n"; } if (version_compare($e->getVersion(), '4.2.20') < 0) { echo "Normalize sort order for aff banners and links..."; if (ob_get_level ()) ob_end_flush(); $this->getDi()->db->query("SET @i = 0"); $this->getDi()->db->query("UPDATE ?_aff_banner SET sort_order=(@i:=@i+1) ORDER BY IF(sort_order = 0, ~0, sort_order)"); echo "Done
\n"; } if (version_compare($e->getVersion(), '4.3.6') < 0) { echo "Define relation between commission and void..."; if (ob_get_level ()) ob_end_flush(); $rows = $this->getDi()->db->select("SELECT c.commission_id AS comm_id, v.commission_id AS void_id FROM ?_aff_commission c LEFT JOIN ?_aff_commission v ON v.record_type = 'void' AND c.invoice_id = v.invoice_id AND (c.invoice_payment_id = v.invoice_payment_id OR (c.invoice_payment_id IS NULL AND v.invoice_payment_id IS NULL)) AND c.product_id = v.product_id AND c.tier=v.tier AND c.invoice_item_id = v.invoice_item_id WHERE c.record_type = 'commission' AND c.is_voided = 0 AND v.commission_id IS NOT NULL"); foreach ($rows as $row) { $comm_id = $row['comm_id']; $void_id = $row['void_id']; $comm = $this->getDi()->affCommissionTable->load($comm_id); $void = $this->getDi()->affCommissionTable->load($void_id); $comm->updateQuick('is_voided', 1); $void->updateQuick('commission_id_void', $comm->pk()); } echo "Done
\n"; } if (version_compare($e->getVersion(), '4.5.4') < 0) { echo "Switch empty payout method with NULL..."; if (ob_get_level ()) ob_end_flush(); $this->getDi()->db->query("UPDATE ?_user SET aff_payout_type=NULL WHERE aff_payout_type=?", ''); echo "Done
\n"; } if (version_compare($e->getVersion(), '4.7.0') < 0) { echo "Set Up Affiliate Signup Form..."; $this->setUpAffFormIfNotExist($this->getDi()->db); echo "Done
\n"; } if (version_compare($e->getVersion(), '5.1.3') <= 0) { echo "Populate config option for backward compatibility..."; Am_Config::saveValue('aff.custom_redirect_other_domains', 1); echo "Done
\n"; } } public function onEmailTemplateTagSets(Am_Event $event) { $tagSets = $event->getReturn(); $tagSets['user']['%user.aff_link%'] = ___('User Affiliate Link'); $tagSets['affiliate'] = array( '%affiliate.name_f%' => 'Affiliate First Name', '%affiliate.name_l%' => 'Affiliate Last Name', '%affiliate.login%' => 'Affiliate Username', '%affiliate.email%' => 'Affiliate E-Mail', '%affiliate.user_id%' => 'Affiliate Internal ID#', '%affiliate.street%' => 'Affiliate Street', '%affiliate.street2%' => 'Affiliate Street (Second Line)', '%affiliate.city%' => 'Affiliate City', '%affiliate.state%' => 'Affiliate State', '%affiliate.zip%' => 'Affiliate ZIP', '%affiliate.country%' => 'Affiliate Country' ); foreach ($this->getDi()->userTable->customFields()->getAll() as $field) { if (@$field->sql && @$field->from_config) { $tagSets['affiliate']['%affiliate.' . $field->name . '%'] = 'Affiliate ' . $field->title; } } $tagSets['affiliate']['%affiliate.aff_link%'] = ___('Affiliate Affiliate Link'); $event->setReturn($tagSets); } public function onMailTemplateBeforeParse(Am_Event $event) { $template = $event->getTemplate(); $tConfig = $template->getConfig(); $mailBody = (!empty($tConfig['bodyText'])) ? $tConfig['bodyText'] : $tConfig['bodyHtml']; foreach (array('user', 'affiliate') as $prefix) { if (strpos($mailBody, "%$prefix.aff_link%") !== false) { $user = $template->$prefix; $user->aff_link = $this->getGeneralAffLink($user); } } } public function onMailSimpleTemplateBeforeParse(Am_Event $event) { $template = $event->getTemplate(); $body = $event->getBody(); $subject = $event->getSubject(); foreach (array('user', 'affiliate') as $prefix) { if (strpos($body, "%$prefix.aff_link%") !== false) { $user = $this->getDi()->userRecord->fromRow($template->$prefix); $tmp = $template->$prefix; $tmp['aff_link'] = $this->getGeneralAffLink($user); $template->$prefix = $tmp; } } } public function onInitFinished() { $this->getDi()->blocks->add(new Am_Block('member/main/top', null, 'aff-member-payout-empty', null, array($this, 'renderAlert'))); $this->getDi()->blocks->add(new Am_Block('aff/top', null, 'aff-aff-payout-empty', null, array($this, 'renderAlert'))); if (($admin = $this->getDi()->authAdmin->getUser()) && $admin->hasPermission(self::ADMIN_PERM_ID)) { $this->getDi()->blocks->add(new Am_Block('admin/user/invoice/details', null, 'aff-user-invoice-details', null, array($this, '_renderInvoiceCommissions'))); $this->getDi()->blocks->add(new Am_Block('admin/user/invoice/top', null, 'aff-user-invoice-top', null, 'admin-void-commission.phtml')); $this->getDi()->blocks->add(new Am_Block('admin/user/invoice/top', null, 'aff-user-invoice-top-comm', null, 'admin-calc-commission.phtml')); } $router = $this->getDi()->router;; $router->addRoute('aff-go', new Am_Mvc_Router_Route( 'aff/go/:r', array( 'module' => 'aff', 'controller' => 'go', 'action' => 'index' ) )); $router->addRoute('aff-banner', new Am_Mvc_Router_Route( 'b/:code/:affiliate', array( 'module' => 'aff', 'controller' => 'banner', 'action' => 'index' ) )); } function getGeneralAffLink(User $user) { return $this->getDi()->url('aff/go/'.urlencode($user->login),null,false,2); } function getClickJs() { $root_url = json_encode($this->getDi()->url('aff/click-js/', null,false,2)); $root_surl = json_encode($this->getDi()->url('aff/click-js/', null,false,true)); return << (function(){ var url=(("https:" == document.location.protocol) ? {$root_surl} : {$root_url} ); var d=document, s=d.createElement('script'), src=d.getElementsByTagName('script')[0]; var w = window; var lo = w.location; var hr=lo.href; var ho=lo.host; var se=lo.search; var m = RegExp('[?&]ref=([^&]*)').exec(se); var k = RegExp('[?&]keyword=([^&]*)').exec(se); var ref = m && decodeURIComponent(m[1].replace(/\+/g, ' ')); var keyword = k && k[1]; s.type='text/javascript';s.async=true; var jssrc = url+'?r='+ref+'&s='+encodeURIComponent(document.referrer); if (k) jssrc = jssrc + '&keyword=' + keyword; s.src=jssrc; if(ref){src.parentNode.insertBefore(s,src); var uri = hr.toString().split(ho)[1]; uri = uri.replace(m[0], ""); if (k) uri = uri.replace(k[0], ""); w.history.replaceState('Object', 'Title', uri);}})(); EOT; } function onBeforeRender(Am_Event $e) { $view = $e->getView(); $tmpl = $e->getTemplateName(); if (!defined('AM_ADMIN') && !$view->jsClickCodeAdded) { $view->jsClickCodeAdded = true; $view->placeholder('body-finish')->prepend($this->getClickJs()); } } function getRedirectUrl($url) { $redirect_url = parse_url($url); if (!is_array($redirect_url)) return; if (array_key_exists('host', $redirect_url) && !$this->getConfig('custom_redirect_other_domains')) { $match = false; foreach (array(ROOT_URL, ROOT_SURL) as $u) { $amember_url = parse_url($u); if (Am_License::getMinDomain($amember_url['host']) == Am_License::getMinDomain($redirect_url['host'])) $match = true; } } else { $match = true; } if ($match) return $url; } protected static function setUpAffFormIfNotExist(DbSimple_Interface $db) { if (!$db->selectCell("SELECT COUNT(*) FROM ?_saved_form WHERE type=?", 'aff')) { $max = $db->selectCell("SELECT MAX(sort_order) FROM ?_saved_form"); $db->query("INSERT INTO ?_saved_form (title, comment, type, fields, sort_order) VALUE (?a)", array( 'Affiliate Signup Form', '', 'aff', '[{"id":"name","class":"name","hide":"1"},{"id":"email","class":"email","hide":true},{"id":"login","class":"login","hide":true},{"id":"password","class":"password","hide":true},{"id":"address","class":"address","hide":"1","config":{"fields":{"street":1,"city":1,"country":1,"state":1,"zip":1}}},{"id":"payout","class":"payout"}]', ++$max )); } } }PK)\6 module.xmlnu[ aff Affiliate This module handles management of affiliate program 4.7.0 PK)\xq*controllers/AffPayoutDetailsController.phpnu[getDi()->affPayoutDetailTable; } }PK)\yKX controllers/SignupController.phpnu[hook->call(Am_Event::LOAD_BRICKS); } parent::init(); $this->msg = ___('We review all affiliates manually, so your affiliate account status is pending. '. 'You will receive email when your account will be approved. Thank you for your patience.'); } function indexAction() { if(!$this->getDi()->auth->getUserId()) $this->getDi()->auth->checkExternalLogin($this->getRequest()); if ($this->getDi()->auth->getUserId() && $this->getDi()->auth->getUser()->is_affiliate) $this->_redirect('aff/aff'); // there are no reasons to use this form if logged-in $form = $this->getDi()->savedFormTable->getByType(SavedForm::D_AFF); if (!$form) { throw new Am_Exception_QuietError(___('There are no form available for affiliate signup.')); } $this->record = $form; $this->view->title = $this->record->title; if ($this->record->meta_title) $this->view->meta_title = $this->record->meta_title; if ($this->record->meta_keywords) $this->view->headMeta()->setName('keywords', $this->record->meta_keywords); if ($this->record->meta_description) $this->view->headMeta()->setName('description', $this->record->meta_description); if ($this->record->meta_robots) $this->view->headMeta()->setName('robots', $this->record->meta_robots); $this->view->code = $this->record->code; $this->view->record = $this->record; $this->form = new Am_Form_Signup(); $this->form->setParentController($this); $this->form->initFromSavedForm($this->record); try { $this->form->run(); } catch (HTML_QuickForm2_NotFoundException $e) { if ($this->getDi()->auth->getUserId()) { $user = $this->getDi()->auth->getUser(); $user->is_affiliate = $this->getModule()->getConfig('signup_type') == 2 ? 0 : 1; $user->save(); if (!$user->is_affiliate) { $this->getModule()->sendNotApprovedEmail($user); $this->view->content = '
' . $this->msg . '
'; $this->view->display('layout.phtml'); } else { $this->_redirect('aff/aff'); } } else { throw $e; } } } function display(Am_Form $form, $pageTitle) { $this->view->form = $form; $this->view->title = $this->record->title; if ($pageTitle) $this->view->title = $pageTitle; $this->view->display($this->record->tpl ? ('signup/' . basename($this->record->tpl)) : 'signup/signup.phtml'); } function process(array $vars, $name, HTML_QuickForm2_Controller_Page $page) { $this->vars = $vars; $em = $page->getController()->getSessionContainer()->getOpaque('EmailCode'); // do actions here $this->user = $this->getDi()->auth->getUser(); if (!$this->user) { $this->user = $this->getDi()->userRecord; $this->user->setForInsert($this->vars); // vars are filtered by the form ! if (empty($this->user->login)) $this->user->generateLogin(); if (empty($this->vars['pass'])) $this->user->generatePassword(); else { $this->user->setPass($this->vars['pass']); } if($this->getDi()->config->get('aff.signup_type')==2) $this->user->is_approved = 0; if (empty($this->user->lang)) $this->user->lang = $this->getDi()->locale->getLanguage(); $this->user->is_affiliate = 1; $this->user->insert(); $this->getDi()->hook->call(Am_Event::SIGNUP_USER_ADDED, array( 'vars' => $this->vars, 'user' => $this->user, 'form' => $this->form, )); } else { unset($this->vars['pass']); unset($this->vars['login']); unset($this->vars['email']); $this->user->setForUpdate($this->vars)->update(); $this->user->is_affiliate = $this->getModule()->getConfig('signup_type') == 2 ? 0 : 1; $this->user->save(); // user updated $this->getDi()->hook->call(Am_Event::SIGNUP_USER_UPDATED, array( 'vars' => $this->vars, 'user' => $this->user, 'form' => $this->form, 'savedForm' => $this->record )); } // remove verification record if (!empty($em)) $this->getDi()->store->delete(Am_Form_Signup_Action_SendEmailCode::STORE_PREFIX . $em); $page->getController()->destroySessionContainer(); $this->getDi()->hook->call(Am_Event::SIGNUP_AFF_ADDED, array( 'vars' => $this->vars, 'user' => $this->user, 'form' => $this->form, )); if($this->user->isApproved() && !$this->getDi()->auth->getUserId()) { $this->getDi()->auth->setUser($this->user, $_SERVER['REMOTE_ADDR']); } if ($this->getDi()->config->get('aff.registration_mail') && $this->user->isApproved()) { $this->getDi()->modules->get('aff')->sendAffRegistrationEmail($this->user); } $this->getDi()->modules->get('aff')->sendAdminRegistrationEmail($this->user); if(!$this->user->isApproved() || !$this->user->is_affiliate){ $this->getModule()->sendNotApprovedEmail($this->user); $this->view->content = '
' . $this->msg . '
'; $this->view->display('layout.phtml'); } else { $this->_redirect('aff/aff'); } return true; } function getCurrentUrl() { $c = $this->getFiltered('c'); return $this->_request->getScheme() . '://' . $this->_request->getHttpHost() . $this->_request->getBaseUrl() . '/' . $this->_request->getModuleName() . '/' . $this->_request->getControllerName(); } }PK)\4ð11controllers/AffController.phpnu[hook->call(Am_Event::LOAD_BRICKS); } parent::init(); } public function preDispatch() { $this->getDi()->auth->requireLogin($this->getDi()->url('aff/aff', null, false)); if ($this->getRequest()->getActionName() != 'enable-aff') if (!$this->getDi()->user->is_affiliate) $this->_redirect('member'); } public function indexAction() { return $this->linksAction(); } public function linksAction() { $catActive = $this->getParam('c', null); $affBanners = $this->getDi()->affBannerTable->findActive($catActive); $user_group_ids = $this->getDi()->user->getGroups(); foreach ($affBanners as $k => $v) { if ($v->user_group_id && !array_intersect($user_group_ids, explode(',', $v->user_group_id))) unset($affBanners[$k]); } $affDownloads = $catActive ? null : $this->getDi()->uploadTable->findByPrefix('affiliate'); if ($catActive) { $this->view->getHelper('breadcrumbs')->setPath(array( $this->getDi()->url('aff/aff') => ___('Affiliate info'), $catActive)); } $this->view->assign('intro', $this->getModule()->getConfig('intro')); $this->view->assign('canUseCustomRedirect', $this->canUseCustomRedirect($this->getDi()->user)); $this->view->assign('catActive', $catActive); $this->view->assign('category', $this->getDi()->affBannerTable->getCategories(true)); $this->view->assign('generalLink', $this->getModule()->getGeneralAffLink($this->getDi()->auth->getUser())); $this->view->assign('affDownloads', $affDownloads); $this->view->assign('affBanners', $affBanners); $this->view->display('aff/links.phtml'); } public function enableAffAction() { // if ($this->getDi()->config->get('aff.signup_type') == 2) { // throw new Am_Exception_AccessDenied('Signup disabled in config'); // } //backwards $this->_redirect('/aff/signup'); } public function statsAction() { $this->_forward('stats', 'member'); } //lowercase becuase of ?action=payout_info does not work with payoutInfoAction public function payoutinfoAction() { $this->_forward('payout-info', 'member'); } public function clinkAction() { $user = $this->getDi()->auth->getUser(); if ($this->canUseCustomRedirect($user)) { $url = $this->getModule()->getRedirectUrl($this->getParam('url', '')); if (!$url) { $link = $this->getDi()->url('aff/go/'.urlencode($user->login),null,false,2); } else { if ($this->getDi()->config->get('aff.tracking_code') && $this->pageHaveTrackingCode($url)) { $link = $this->getRefLink($user->login, $url); } else { $link = $this->getDi()->url('aff/go/'.urlencode($user->login),array('cr'=>base64_encode($url)),false,2); } } } else { $link = $this->getDi()->url('aff/go/'.urlencode($user->login),null,false,2); } $this->_response->ajaxResponse(array( 'link' => $link, )); } protected function canUseCustomRedirect(User $user) { $cr = $this->getModule()->getConfig('custom_redirect'); return ($cr == Bootstrap_Aff::AFF_CUSTOM_REDIRECT_ALLOW_SOME_DENY_OTHERS && $user->aff_custom_redirect) || ($cr == Bootstrap_Aff::AFF_CUSTOM_REDIRECT_DENY_SOME_ALLOW_OTHERS && !$user->aff_custom_redirect); } /** * Check whereever given url have tracking code included * @param type $url */ function pageHaveTrackingCode($url) { $req = new Am_HttpRequest($url, Am_HttpRequest::METHOD_GET); try { $resp = $req->send(); } catch (Exception $e) { $this->getDi()->errorLogTable->logException($e); return false; } if (strpos($resp->getBody(), "id='am-ctcs-v1'") !== false) return true; return false; } function getRefLink($login, $url) { $url = parse_url($url); parse_str(@$url['query'], $query); $query['ref'] = $login; $url['query'] = http_build_query($query); return sprintf("%s://%s%s%s", $url['scheme'], $url['host'], $url['path'] ? $url['path'] : '/', $url['query'] ? "?" . $url['query'] : ''); } } PK)\++controllers/GoController.phpnu[getParam('r')); if (is_numeric($id)) { $aff = $this->getDi()->userTable->load($id, false); if ($aff) return $aff; } if (strlen($id)) { $aff = $this->getDi()->userTable->findFirstByLogin($id); if ($aff) return $aff; } return null; } function findKeyword() { if($keyword = $this->getParam('keyword')) { return substr($keyword, 0, Bootstrap_Aff::KEYWORD_MAX_LEN); } return null; } function findAm3Aff() { $id = $this->getFiltered('r'); if ($id > 0) { $newid = $this->getDi()->getDbService()->selectCell("SELECT id from ?_data where `key`='am3:id' AND `table`='user' and value=?",$id); if ($newid > 0) { $aff = $this->getDi()->userTable->load($newid, false); if ($aff) return $aff; } } return null; } function findUrl() { $link = $this->getInt('i'); if ($link > 0 ) { $this->banner = $this->getDi()->affBannerTable->load($link, false); return $this->banner->url; } else { //try to find custom redirect url if($this->aff) { if($custom_url = $this->getParam('cr')) { $cr = Am_Di::getInstance()->config->get('aff.custom_redirect'); if(($cr == Bootstrap_Aff::AFF_CUSTOM_REDIRECT_ALLOW_SOME_DENY_OTHERS && $this->aff->aff_custom_redirect) || ($cr == Bootstrap_Aff::AFF_CUSTOM_REDIRECT_DENY_SOME_ALLOW_OTHERS && !$this->aff->aff_custom_redirect)) { if($url = base64_decode($custom_url)) { return $this->getModule()->getRedirectUrl($url); } } } } return $this->getModule()->getConfig('general_link_url', null); } } function indexAction() { $this->aff = $this->findAff(); $event = new Am_Event(Am_Event::GET_AFF_REDIRECT_LINK, array('aff' => $this->aff)); $event->setReturn($this->findUrl()); $this->getDi()->hook->call($event); $this->link = $event->getReturn(); /// log click if ($this->aff) { $keyword = $this->findKeyword(); $aff_click_id = $this->getDi()->affClickTable->log($this->aff, $this->banner, null, $this->getModule()->findKeywordId($this->aff->pk(), $keyword)); $this->getModule()->setCookie($this->aff, $this->banner ? $this->banner : null, $aff_click_id); $this->getModule()->setKeywordCookie($this->aff, $keyword); } $this->_redirect($this->link ?: '', array('prependBase'=>false)); } function findAm3Url() { $r = $this->getFiltered('i'); $r_id = substr($r,1); $r_type = substr($r,0,1); if ($r_id > 0 && $r_type) { $url = $this->getDi()->db->selectCell("SELECT url from ?_aff3_banner where banner_link_id=? and type=?",$r_id,$r_type); return $url ?: $this->getModule()->getConfig('general_link_url', null); } else { return $this->getModule()->getConfig('general_link_url', null); } } function am3goAction() { $this->aff = $this->findAm3Aff(); $event = new Am_Event(Am_Event::GET_AFF_REDIRECT_LINK, array('aff' => $this->aff)); $event->setReturn($this->findAm3Url()); $this->getDi()->hook->call($event); $this->link = $event->getReturn(); /// log click if ($this->aff) { $aff_click_id = $this->getDi()->affClickTable->log($this->aff, $this->banner,null, $this->getModule()->findKeywordId($this->aff->pk())); $this->getModule()->setCookie($this->aff, $this->banner ? $this->banner : null, $aff_click_id); } $this->_redirect($this->link ?: '', array('prependBase'=>false)); } }PK)\̩ controllers/BannerController.phpnu[affBanner = $affBanner; $this->aff = $aff; } public static function create(AffBanner $affBanner, User $aff) { switch ($affBanner->type) { case AffBanner::TYPE_TEXTLINK : return new Am_BannerRenderer_TextLink($affBanner, $aff); case AffBanner::TYPE_BANNER : return new Am_BannerRenderer_Banner($affBanner, $aff); case AffBanner::TYPE_LIGHTBOX : return new Am_BannerRenderer_Lightbox($affBanner, $aff); case AffBanner::TYPE_CUSTOM : return new Am_BannerRenderer_Custom($affBanner, $aff); default: throw new Am_Exception_InternalError('Can not instantiate banner with type : ' . $affBanner->type); } } abstract protected function _getCode(); public function getCode() { $w = json_encode($this->_getCode()); return <<url('aff/go/'.urlencode($this->aff->login), array('i' => $this->affBanner->pk()), false, 2); } } class Am_BannerRenderer_TextLink extends Am_BannerRenderer { protected function _getCode() { return sprintf('%s', $this->getUrl(), $this->affBanner->title ); } } class Am_BannerRenderer_Custom extends Am_BannerRenderer { protected function _getCode() { return str_replace('%url%', $this->getUrl(), $this->affBanner->html); } } class Am_BannerRenderer_Banner extends Am_BannerRenderer { protected function _getCode() { $upload = Am_Di::getInstance()->uploadTable->load($this->affBanner->upload_id); return sprintf('%s', $this->getUrl(), Am_Di::getInstance()->url(array('file/get/path/%s/i/%d', preg_replace('/^\./', '', $upload->getPath()), $this->aff->pk()), null,true,2), Am_Html::escape($this->affBanner->title), ($this->affBanner->width ? sprintf('width="100%%" style="max-width:%dpx"', $this->affBanner->width) : '') ); } } class Am_BannerRenderer_Lightbox extends Am_BannerRenderer { protected function _getCode() { $upload = Am_Di::getInstance()->uploadTable->load($this->affBanner->upload_id); $upload_big = Am_Di::getInstance()->uploadTable->load($this->affBanner->upload_big_id); return sprintf(' %s', $this->getDi()->url(array('file/get/path/%s/i/%d',preg_replace('/^\./', '', $upload_big->getPath()),$this->aff->pk()), null,true,2), $this->getUrl(), $this->affBanner->title, Am_Di::getInstance()->url(array('file/get/path/%s/i/%d',preg_replace('/^\./', '', $upload->getPath()),$this->aff->pk()), null,true,2), Am_Html::escape($this->affBanner->title) ); } public function getCode() { $url = ROOT_URL; $a_url = $url . '/application/aff/views/public/img/'; $l_url = $url . '/application/aff/views/public/js/jquery.lightbox.js'; $s_url = $url . '/application/aff/views/public/css/jquery.lightbox.css'; $w = json_encode($this->_getCode()); return <<getDi()->security->reveal($this->getParam('code'))) && $banner = $this->getDi()->affBannerTable->load($id, false)) { $affiliate = $this->getParam('affiliate'); $bannerRenderer = Am_BannerRenderer::create($banner, $this->getDi()->userTable->findFirstByLogin($affiliate)); header('Content-type: ' . Upload::getMimeType('js')); echo $bannerRenderer->getCode(); } } }PK)\HrJJ)controllers/AdminCommissionController.phpnu[getParam('filter')) { foreach ($this->filterMap as $alias => $fields) { foreach ($fields as $field) { $c = new Am_Query_Condition_Field($field, 'LIKE', '%' . $filter . '%', $alias); if (!$condition) $condition = $c; else $condition->_or($c); } } $this->grid->getDataSource()->getDataSourceQuery() ->add($condition); } if ($filter = $this->getParam('dat1')) { $this->grid->getDataSource()->getDataSourceQuery() ->addWhere("t.{$this->datField} >= ?", Am_Form_Element_Date::createFromFormat(null, $filter)->format('Y-m-d 00:00:00')); } if ($filter = $this->getParam('dat2')) { $this->grid->getDataSource()->getDataSourceQuery() ->addWhere("t.{$this->datField} <= ?", Am_Form_Element_Date::createFromFormat(null, $filter)->format('Y-m-d 23:59:59')); } } abstract protected function getPlaceholder(); function renderInputs() { $prefix = $this->grid->getId(); $dat1 = @$this->vars['dat1']; $dat2 = @$this->vars['dat2']; $filter = @$this->vars['filter']; $start = ___('Start Date'); $end = ___('End Date'); $text_filter_title = $this->getPlaceholder(); return << CUT; } function getTitle() { return ''; } } class Am_Grid_Filter_Commission extends Am_Grid_Filter_Aff_Abstract { protected $varList = array('filter', 'dat1', 'dat2', 'type'); protected $datField = 'date'; protected $filterMap = array( 'a' => array('name_f', 'name_l', 'login'), 'u' => array('name_f', 'name_l', 'login'), 'p' => array('title') ); function renderInputs() { return $this->renderInputSelect('type', array( '' => ___('All'), AffCommission::COMMISSION => ___('Commission'), AffCommission::VOID => ___('Void'), 'not-in-payout' => ___('Not Included to Payout') )) . ' ' . parent::renderInputs(); } protected function applyFilter() { parent::applyFilter(); if ($type = $this->getParam('type')) { switch ($type) { case 'not-in-payout': $this->grid->getDataSource()->getDataSourceQuery() ->addWhere('ap.date IS NULL'); break; default: $this->grid->getDataSource()->getDataSourceQuery() ->addWhere('record_type=?', $type); } } } protected function getPlaceholder() { return ___('Filter by Affiliate/User/Product'); } } class Am_Grid_Filter_Clicks extends Am_Grid_Filter_Aff_Abstract { protected $datField = 'time'; protected $filterMap = array( 't' => array('remote_addr'), 'a' => array('name_f', 'name_l', 'login'), 'b' => array('title') ); protected function getPlaceholder() { return ___('Filter by Affiliate/Banner/IP'); } } class Am_Grid_Filter_Leads extends Am_Grid_Filter_Aff_Abstract { protected $datField = 'time'; protected $filterMap = array( 'a' => array('name_f', 'name_l', 'login'), 'u' => array('name_f', 'name_l', 'login'), 'b' => array('title') ); protected function getPlaceholder() { return ___('Filter by Affiliate/User/Banner'); } } class Am_Grid_Filter_TopAffiliate extends Am_Grid_Filter_Abstract { protected $varList = array('dat1', 'dat2', 'pid'); protected function applyFilter() { if ($filter = $this->getParam('pid')) { $this->grid->getDataSource()->getDataSourceQuery() ->addWhere("c.product_id IN (?a)", $filter); } if ($filter = $this->getParam('dat1')) { $this->grid->getDataSource()->getDataSourceQuery() ->addWhere("c.date >= ?", Am_Form_Element_Date::createFromFormat(null, $filter)->format('Y-m-d')); } if ($filter = $this->getParam('dat2')) { $this->grid->getDataSource()->getDataSourceQuery() ->addWhere("c.date <= ?", Am_Form_Element_Date::createFromFormat(null, $filter)->format('Y-m-d')); } } function renderInputs() { $prefix = $this->grid->getId(); $pid = @$this->vars['pid']; $dat1 = @$this->vars['dat1']; $dat2 = @$this->vars['dat2']; $start = ___('Start Date'); $end = ___('End Date'); $options = Am_Html::renderOptions(Am_Di::getInstance()->productTable->getOptions(), $pid); return <<
CUT; } function getTitle() { return ''; } } class Aff_AdminCommissionController extends Am_Mvc_Controller_Pages { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Aff::ADMIN_PERM_ID); } public function initPages() { $this->addPage(array($this, 'createGrid'), 'commissions', ___('Commissions')); $this->addPage(array($this, 'createClicksGrid'), 'clicks', ___('Clicks')); $this->addPage(array($this, 'createLeadsGrid'), 'leads', ___('Leads')); $this->addPage(array($this, 'createTopAffiliateGrid'), 'top-affiliate', ___('Top Affiliates')); } public function createGrid() { $hasCustomRules = $this->getDi()->affCommissionRuleTable->hasCustomRules(); $hasTiers = $this->getDi()->affCommissionRuleTable->getMaxTier(); $ds = new Am_Query($this->getDi()->affCommissionTable); $ds->leftJoin('?_invoice', 'i', 'i.invoice_id=t.invoice_id'); $ds->leftJoin('?_user', 'u', 'u.user_id=i.user_id'); $ds->leftJoin('?_user', 'a', 't.aff_id=a.user_id'); $ds->leftJoin('?_product', 'p', 't.product_id=p.product_id'); $ds->leftJoin('?_aff_payout_detail', 'apd', 't.payout_detail_id=apd.payout_detail_id'); $ds->leftJoin('?_aff_payout', 'ap', 'ap.payout_id=apd.payout_id'); $ds->addField('ap.date', 'payout_date'); $ds->addField('ap.type', 'payout_type'); $ds->addField('ap.payout_id'); $ds->addField('TRIM(REPLACE(CONCAT(a.login, \' (\', a.name_f, \' \', a.name_l,\') #\', a.user_id), \'( )\', \'\'))', 'aff_name') ->addField('a.login', 'aff_login') ->addField('CONCAT(a.name_f, \' \', a.name_l)', 'aff_fullname') ->addField('a.email', 'aff_email') ->addField('u.user_id', 'user_id') ->addField('TRIM(REPLACE(CONCAT(u.login, \' (\',u.name_f, \' \',u.name_l,\') #\', u.user_id), \'( )\', \'\'))', 'user_name') ->addField('u.login', 'user_login') ->addField('CONCAT(u.name_f, \' \', u.name_l)', 'user_fullname') ->addField('u.email', 'user_email') ->addField('p.title', 'product_title') ->addField('i.public_id') ->setOrder('commission_id', 'desc'); $grid = new Am_Grid_Editable('_affcomm', ___('Affiliate Commission'), $ds, $this->_request, $this->view); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $grid->actionsClear(); $userUrl = new Am_View_Helper_UserUrl(); $grid->addField(new Am_Grid_Field_Date('date', ___('Date')))->setFormatDate(); $grid->addField('aff_name', ___('Affiliate')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{aff_id}'), '_top')); $grid->addField('user_name', ___('User')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{user_id}'), '_top')); $grid->addField('product_title', ___('Product')); $grid->addField('invoice_id', ___('Invoice')) ->setGetFunction(array($this, '_getInvoiceNum')) ->addDecorator( new Am_Grid_Field_Decorator_Link( 'admin-user-payments/index/user_id/{user_id}#invoice-{invoice_id}', '_top')); $fieldAmount = $grid->addField('amount', ___('Amount'))->setRenderFunction(array($this, 'renderAmount')); $grid->addField('payout_date', ___('Payout Date')) ->setRenderFunction(array($this, 'renderPayout')); $grid->addField('payout_type', ___('Payout Type')) ->setRenderFunction(function($r, $fn, $g, $fo) { return $g->renderTd($r->payout_type ?: '–', false); }); if ($hasTiers) { $grid->addField('tier', ___('Tier')) ->setRenderFunction(array($this, 'renderTier')); } if ($hasCustomRules) { $grid->addField(new Am_Grid_Field_Expandable('commission_id', '', false)) ->setPlaceholder(___('Used Rules')) ->setAjax($this->getDi()->url('aff/admin-commission/get-rules?id={commission_id}'), null, false); } $grid->setFilter(new Am_Grid_Filter_Commission()); $grid->actionAdd(new Am_Grid_Action_Total())->addField($fieldAmount, "IF(record_type='void', -1*t.%1\$s, t.%1\$s)"); $grid->actionAdd(new Am_Grid_Action_Aff_Void()); $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'cbGetTrAttribs')); $invoiceField = new Am_Grid_Field('invoice_id', ___('Invoice')); $invoiceField->setGetFunction(array($this, '_getInvoiceNum')); $export = new Am_Grid_Action_Export; $export ->addField(new Am_Grid_Field('date', ___('Date'))) ->addField(new Am_Grid_Field('aff_name', ___('Affiliate'))) ->addField(new Am_Grid_Field('aff_login', ___('Affiliate Login'))) ->addField(new Am_Grid_Field('aff_fullname', ___('Affiliate Name'))) ->addField(new Am_Grid_Field('aff_email', ___('Affiliate Email'))) ->addField(new Am_Grid_Field('user_name', ___('User'))) ->addField(new Am_Grid_Field('user_login', ___('User Login'))) ->addField(new Am_Grid_Field('user_fullname', ___('User Name'))) ->addField(new Am_Grid_Field('user_email', ___('User Email'))) ->addField(new Am_Grid_Field('product_title', ___('Product'))) ->addField($invoiceField) ->addField(new Am_Grid_Field('amount', ___('Amount'))) ->addField(new Am_Grid_Field('payout_date', ___('Payout Date'))) ->addField(new Am_Grid_Field('payout_type', ___('Payout Type'))); $grid->actionAdd($export); return $grid; } public function createTopAffiliateGrid() { $q = new Am_Query($this->getDi()->userTable); $q->addWhere('t.is_affiliate>?', 0); $q->addField("CONCAT(t.name_f, ' ', t.name_l)", 'name'); $q->addField("t.login", 'login'); $q->addField("t.user_id", 'user_id'); $q->leftJoin('?_aff_commission', 'c', 'c.aff_id=t.user_id'); $q->addWhere('c.tier=0'); $q->addField("SUM(IF(record_type='commission', amount, -amount))", 'comm'); $q->addField("SUM(IF(record_type='commission', 1, 0))", 'cnt'); $q->addHaving('comm>?', 0); $grid = new Am_Grid_ReadOnly('_ta', ___('Top Affiliates'), $q, $this->getRequest(), $this->view); $grid->addField('login', ___('Username')) ->addDecorator(new Am_Grid_Field_Decorator_Link($this->view->userUrl('{user_id}'))); $grid->addField('name', ___('Name')); $grid->addField('cnt', ___('Sales Count'), true, 'right'); $grid->addField('comm', ___('Commission')) ->setRenderFunction(function($r, $fn, $g, $fo){ return sprintf('%s', Am_Currency::render($r->$fn)); }); $grid->setFilter(new Am_Grid_Filter_TopAffiliate); return $grid; } public function getRulesAction() { $title_removed = ___('Rule Removed'); $id = $this->getParam('id'); $r = $this->getDi()->db->selectCell("SELECT GROUP_CONCAT(CONCAT('#', ccr.rule_id, ' - ', IFNULL(cr.comment, ?)) SEPARATOR '
') used_rules FROM ?_aff_commission_commission_rule ccr LEFT JOIN ?_aff_commission_rule cr ON ccr.rule_id = cr.rule_id WHERE ccr.commission_id=?", "$title_removed", $id); echo $r ? $r : ___('Information is not available'); } public function cbGetTrAttribs(& $ret, $record) { if ($record->record_type == AffCommission::VOID) { $ret['class'] = isset($ret['class']) ? $ret['class'] . ' red' : 'red'; } } function _getInvoiceNum(Am_Record $invoice) { return $invoice->invoice_id . '/' . $invoice->public_id; } public function renderPayout(Am_Record $record, $f, $g) { $out = $record->payout_detail_id ? sprintf('%s', $this->getDi()->url('aff/admin-payout/view', array('payout_id'=>$record->payout_id)), amDate($record->payout_date)): '–'; return $g->renderTd($out, false); } public function renderTier(AffCommission $record) { return sprintf('%s', $record->tier ? ___('%d-Tier', $record->tier + 1) : '–'); } public function voidAction() { $record = $this->getDi()->affCommissionTable->load($this->_request->get('id')); if(!$record->is_voided) { $this->getDi()->affCommissionTable->void($record); $invoice = $this->getDi()->invoiceTable->load($record->invoice_id); echo $this->getModule()->renderInvoiceCommissions($invoice, $this->view); } } public function calcAction() { $invoice = $this->getDi()->invoiceTable->load($this->_request->get('id')); $invoice_payment_ids = $this->getDi()->db->selectCol("SELECT invoice_payment_id from ?_aff_commission where invoice_id = ?", $invoice->pk()); if (@count($invoice_payment_ids) < $invoice->getPaymentsCount()) { foreach ($invoice->getPaymentRecords() as $payment) if(!@in_array($payment->pk(), $invoice_payment_ids)) $this->getDi()->affCommissionRuleTable->processPayment($invoice, $payment); echo $this->getModule()->renderInvoiceCommissions($invoice, $this->view); } else throw new Am_Exception_InputError('Can not calculate commission for this Invoice. This invoice already has associated commission records'); } public function createClicksGrid() { $ds = new Am_Query($this->getDi()->affClickTable); $ds->leftJoin('?_user', 'a', 't.aff_id=a.user_id'); $ds->addField('TRIM(REPLACE(CONCAT(a.login, \' (\', a.name_f, \' \', a.name_l,\') #\', a.user_id), \'( )\', \'\'))', 'aff_name'); $ds->leftJoin('?_aff_banner', 'b', 't.banner_id=b.banner_id'); $ds->addField('b.title', 'banner'); $grid = new Am_Grid_ReadOnly('_affclicks', ___('Clicks'), $ds, $this->_request, $this->view); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $userUrl = new Am_View_Helper_UserUrl(); $grid->addField('time', ___('Date/Time'))->setFormatFunction('amDateTime'); $grid->addField('remote_addr', ___('IP Address')); $grid->addField('banner', 'Banner') ->setRenderFunction(array($this, 'renderBanner')); $grid->addField(new Am_Grid_Field_Expandable('referer', ___('Referer'))) ->setMaxLength(45) ->setPlaceholder(Am_Grid_Field_Expandable::PLACEHOLDER_SELF_TRUNCATE_END); $grid ->addField('aff_name', ___('Affiliate')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{aff_id}'), '_top')); $grid->setFilter(new Am_Grid_Filter_Clicks()); return $grid; } public function createLeadsGrid() { $ds = new Am_Query($this->getDi()->affLeadTable); $ds->leftJoin('?_user', 'a', 't.aff_id=a.user_id'); $ds->addField('TRIM(REPLACE(CONCAT(a.login, \' (\', a.name_f, \' \', a.name_l,\') #\', a.user_id), \'( )\', \'\'))', 'aff_name'); $ds->leftJoin('?_aff_banner', 'b', 't.banner_id=b.banner_id'); $ds->addField('b.title', 'banner'); $ds->leftJoin('?_user', 'u', 'u.user_id=t.user_id'); $ds->addField('TRIM(REPLACE(CONCAT(u.login, \' (\',u.name_f, \' \',u.name_l,\') #\', u.user_id), \'( )\', \'\'))', 'user_name') ->addField('u.email', 'user_email'); $grid = new Am_Grid_ReadOnly('_affclicks', ___('Leads'), $ds, $this->_request, $this->view); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $userUrl = new Am_View_Helper_UserUrl(); $grid->addField('aff_name', ___('Affiliate')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{aff_id}'), '_top')); $grid->addField('user_name', ___('User')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{user_id}'), '_top')); $grid->addField('banner', ___('Banner')) ->setRenderFunction(array($this, 'renderBanner')); $grid->addField('time', ___('Date/Time'))->setFormatFunction('amDateTime'); $grid->addField('first_visited', ___('First visited'))->setFormatFunction('amDateTime'); $grid->setFilter(new Am_Grid_Filter_Leads()); return $grid; } public function renderAmount($record, $field, $grid) { return sprintf('%s', ($record->record_type == AffCommission::VOID ? '− ' : '') . Am_Currency::render($record->amount)); } public function renderBanner($record, $field, $grid) { return sprintf("%s", $record->banner ? Am_Html::escape($record->banner) : '–'); } }PK)\i~:3:3%controllers/AdminPayoutController.phpnu[setAttribute('name', 'payout'); $form->addDate('payout_date') ->setLabel(___('Payout Date')) ->setValue(sqlDate($this->grid->getDi()->dateTime)); foreach ($this->grid->getVariablesList() as $k) { $form->addHidden($this->grid->getId() . '_' . $k)->setValue($this->grid->getRequest()->get($k, "")); } $form->addSaveButton(___("Run Payout")); $form->setDataSources(array($this->grid->getCompleteRequest())); if ($form->isSubmitted() && $form->validate()) { $values = $form->getValue(); $this->grid->getDi()->affCommissionTable->runPayout($values['payout_date']); $this->grid->redirectBack(); } else { echo $this->renderTitle(); echo $form; } } } class Am_Grid_Action_ExportPayout extends Am_Grid_Action_Abstract { protected $type = self::SINGLE; public function __construct($id = null, $title = null) { parent::__construct('export', ___('Export')); } public function run() { $payout = $this->grid->getRecord(); /* @var $payout AffPayout */ if ($this->grid->getCompleteRequest()->get('run')) { $m = $payout->getPayoutMethod(); if (!$m) throw new Am_Exception_InputError("Payout method [$payout->type] is disabled or misconfigured"); $details = new Am_Query($this->grid->getDi()->affPayoutDetailTable); $details->addWhere('payout_id=?d', $payout->pk()); $response = new Am_Mvc_Response; $m->export($payout, $details, $response); $response->sendResponse(); exit(); } else { $link = $this->grid->getActionUrl('export', $payout->pk()) . '&run=1'; printf("%s", Am_Html::escape($link), ___('Download CSV File')); } } } class Am_Grid_Action_PayoutMarkPaid extends Am_Grid_Action_Group_Abstract { public function doRun(array $ids) { if ($ids[0] == self::ALL) { $ids = $this->grid->getDi()->db->selectCol("SELECT payout_detail_id FROM ?_aff_payout_detail WHERE payout_id = ?", $this->grid->getCompleteRequest()->get('payout_id')); Am_Di::getInstance()->db->query("UPDATE ?_aff_payout_detail SET is_paid=1 WHERE payout_id = ?", $this->grid->getCompleteRequest()->get('payout_id')); } else { $this->grid->getDi()->db->query("UPDATE ?_aff_payout_detail SET is_paid=1 WHERE payout_detail_id IN (?a)", $ids); } $this->runHooksIfNecessary($ids, $this->grid->getCompleteRequest()->get('payout_id')); $this->sendEmailsIfNecessary($ids, $this->grid->getCompleteRequest()->get('payout_id')); echo $this->renderDone(); } public function handleRecord($id, $record) { //nop } protected function runHooksIfNecessary($ids, $payout_id) { $di = $this->grid->getDi(); if (!$di->hook->have(Bootstrap_Aff::AFF_PAYOUT_PAID)) return; $payout = $di->affPayoutTable->load($payout_id); foreach ($ids as $id) { $payout_detail = $di->affPayoutDetailTable->load($id); $user = $di->userTable->load($payout_detail->aff_id); $di->hook->call(Bootstrap_Aff::AFF_PAYOUT_PAID, array( 'user' => $user, 'payout' => $payout, 'payoutDetail' => $payout_detail )); } } /** * @param array $ids ids of payout details * @param int $payout_id */ protected function sendEmailsIfNecessary($ids, $payout_id) { $di = $this->grid->getDi(); $payout = $di->affPayoutTable->load($payout_id); $options = Am_Aff_PayoutMethod::getAvailableOptions(); $payout_method_title = isset($options[$payout->type]) ? $options[$payout->type] : $payout->type; if ($di->modules->get('aff')->getConfig('notify_payout_paid')) { foreach ($ids as $id) { $payout_detail = $di->affPayoutDetailTable->load($id); $aff = $di->userTable->load($payout_detail->aff_id); $et = Am_Mail_Template::load('aff.notify_payout_paid', $aff->lang); $et->setPayout_detail($payout_detail); $et->setPayout_method_title($payout_method_title); $et->setPayout($payout); $et->setAffiliate($aff); $et->send($aff); } } } } class Am_Grid_Action_PayoutMarkNotPaid extends Am_Grid_Action_Group_Abstract { public function doRun(array $ids) { if ($ids[0] == self::ALL) { $this->grid->getDi()->db->query("UPDATE ?_aff_payout_detail SET is_paid=0 WHERE payout_id = ?", $this->grid->getCompleteRequest()->get('payout_id')); } else { $this->grid->getDi()->db->query("UPDATE ?_aff_payout_detail SET is_paid=0 WHERE payout_detail_id IN (?a)", $ids); } echo $this->renderDone(); } public function handleRecord($id, $record) { //nop } } class Am_Grid_Action_Total_Payout extends Am_Grid_Action_Abstract { protected $type = self::HIDDEN; public function run() { //nop } public function renderOut(& $out) { $totals = array(); $totals[] = sprintf('%s %s: %s', ___('Total'), ___('To Pay'), Am_Currency::render( Am_Di::getInstance()->db->selectCell("SELECT SUM(amount) from ?_aff_payout_detail"))); $totals[] = sprintf('%s %s: %s', ___('Total'), ___('Paid'), Am_Currency::render( Am_Di::getInstance()->db->selectCell("SELECT SUM(amount) from ?_aff_payout_detail where is_paid > 0"))); $html = sprintf('
%s
', implode(',', $totals)); $out = preg_replace('|(addCallback(Am_Grid_ReadOnly::CB_RENDER_TABLE, array($this, 'renderOut')); /* @var $ds Am_Query */ $this->ds = clone $grid->getDataSource(); parent::setGrid($grid); } } class Aff_AdminPayoutController extends Am_Mvc_Controller_Grid { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Aff::ADMIN_PERM_ID); } function createGrid() { $ds = new Am_Query($this->getDi()->affPayoutTable); $ds->leftJoin('?_aff_payout_detail', 'd', 'd.payout_id=t.payout_id AND d.is_paid>0'); $ds->addField('SUM(amount)', 'paid'); $ds->setOrder('date', 'DESC'); $grid = new Am_Grid_Editable('_payout', ___('Payouts'), $ds, $this->_request, $this->view); $grid->setEventId('gridAffPayout'); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $grid->actionsClear(); $grid->addField(new Am_Grid_Field_Date('date', ___('Payout Date')))->setFormatDate(); $grid->addField(new Am_Grid_Field_Date('thresehold_date', ___('Thresehold Date')))->setFormatDate(); $grid->addField(new Am_Grid_Field_Enum('type', ___('Payout Method'))) ->setTranslations(Am_Aff_PayoutMethod::getAvailableOptions()); $grid->addField('total', ___('Total to Pay'), true, 'right')->setGetFunction(array($this, 'getAmount')); $grid->addField('paid', ___('Total Paid'), true, 'right')->setGetFunction(array($this, 'getAmount')); //$grid->actionAdd(new Am_Grid_Action_Url('run', ___('Run'), '__ROOT__/aff/admin-payout/run?payout_id=__ID__')); $grid->actionAdd(new Am_Grid_Action_Url('view', ___('View'), '__ROOT__/aff/admin-payout/view?payout_id=__ID__')) ->setTarget('_top'); $grid->actionAdd(new Am_Grid_Action_RunPayout('run_payout', ___('Generate Payout Manually'))); $grid->actionAdd(new Am_Grid_Action_ExportPayout()); $grid->actionAdd(new Am_Grid_Action_Delete()) ->setIsAvailableCallback(array($this, 'isDeleteAvailable')); $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'cbGetTrAttribs')); $grid->addCallback(Am_Grid_Editable::CB_RENDER_CONTENT, array($this, 'renderContent')); $grid->actionAdd(new Am_Grid_Action_Total_Payout()); return $grid; } public function isDeleteAvailable($record) { return floatval($record->paid) == 0.0; } public function cbGetTrAttribs(& $ret, $record) { if ($record->total <= $record->paid) { $ret['class'] = isset($ret['class']) ? $ret['class'] . ' disabled' : 'disabled'; } } function viewAction() { Am_Aff_PayoutMethod::static_addFields(); // display payouts list date | method | total | paid | $id = $this->getInt('payout_id'); if (!$id) throw new Am_Exception_InputError("Not payout_id passed"); $ds = new Am_Query($this->getDi()->affPayoutDetailTable); $ds->leftJoin('?_aff_payout', 'p', 'p.payout_id=t.payout_id'); $ds->leftJoin('?_user', 'u', 't.aff_id=u.user_id'); $ds->addField('u.*'); $ds->addField('p.type', 'type'); $ds->addWhere('t.payout_id=?d', $id); $grid = new Am_Grid_Editable('_d', ___("Payout %d Details", $id), $ds, $this->_request, $this->view); $grid->setEventId('gridAffPayoutDetail'); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $grid->addCallback(Am_Grid_Editable::CB_RENDER_TABLE, array($this, 'addBackLink')); $userUrl = new Am_View_Helper_UserUrl(); $grid->addField('email', ___('E-Mail')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{user_id}'), '_top')); $grid->addField('name_f', ___('First Name')); $grid->addField('name_l', ___('Last Name')); $grid->addField(new Am_Grid_Field_Enum('type', ___('Payout Method'))) ->setTranslations(Am_Aff_PayoutMethod::getAvailableOptions()); $grid->addField('amount', ___('Amount'), true, 'right')->setGetFunction(array($this, 'getAmount')); // $grid->addField('receipt_id', ___('Receipt Id')); $grid->addField(new Am_Grid_Field_Enum('is_paid', ___('Is Paid?'))) ->setTranslations(array( 0 => ___('No'), 1 => ___('Yes') )); $grid->addField(new Am_Grid_Field_Expandable('_details', ___('Payout Details'))) ->setGetFunction(array($this, 'getPayoutDetails')); $grid->actionsClear(); //$grid->actionAdd(new Am_Grid_Action_LiveEdit('receipt_id')); $grid->actionAdd(new Am_Grid_Action_PayoutMarkPaid('mark_paid', ___('Mark Paid'))); $grid->actionAdd(new Am_Grid_Action_PayoutMarkNotPaid('mark_notpaid', ___('Mark NOT Paid'))); $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'detailCbGetTrAttribs')); $grid->runWithLayout(); } function detailCbGetTrAttribs(& $ret, $record) { if ($record->is_paid) { $ret['class'] = isset($ret['class']) ? $ret['class'] . ' disabled' : 'disabled'; } } function getPayoutDetails($obj) { $obj = $this->getDi()->userTable->createRecord($obj->toArray()); $type = $obj->aff_payout_type; $pattern = 'aff_' . $type . '_'; $out = ""; foreach ($obj->data()->getAll() as $k => $v) { if (strpos($k, $pattern) !== 0) continue; $field = $this->getDi()->userTable->customFields()->get($k); $out .= sprintf("%s : %s
\n", Am_Html::escape($field ? $field->title : ucfirst(substr($k, strlen($pattern)))), Am_Html::escape($v)); } return $out ? $out : '-no details-'; } function addBackLink(& $out, Am_Grid_ReadOnly $grid) { $out = "" . ___('Return to Payouts List') . "

" . $out; } public function getAmount($record, $grid, $field) { return Am_Currency::render($record->{$field}); } public function renderContent(& $out, Am_Grid_Editable $grid) { $out = '
' . ___('aMember generate payout reports automatically according your settings %shere%s. ' . 'Please note user without defined valid payout method will not be included to this payout report. They should define it first ' . 'in his member area.', '', '') . '
' . $out; } }PK)\PP&controllers/AdminBannersController.phpnu[uploadAcl->checkPermission($this->prefix, Am_Upload_Acl::ACCESS_ALL, Am_Di::getInstance()->authAdmin->getUser())) { throw new Am_Exception_AccessDenied(); } $id = explode('_', get_class($this)); $id = strtolower(array_pop($id)); parent::__construct('_' . $id, ___('Marketing Materials'), $this->createDs(), $request, $view); } function init() { $this->setRecordTitle('File'); $this->setFilter(new Am_Grid_Filter_Text(___('Filter by name or description'), array('name' => 'LIKE', 'desc' => 'LIKE'))); } protected function createDs() { $ds = new Am_Query(Am_Di::getInstance()->uploadTable); $ds->addWhere('prefix=?', $this->prefix); return $ds; } function initActions() { $this->actionAdd(new Am_Grid_Action_Upload()); $this->actionAdd(new Am_Grid_Action_Delete()); $actionDownload = new Am_Grid_Action_Url('download', ___('Download'), $this->getDi()->url('admin-upload/get?id=__ID__')); $actionDownload->setTarget('_top'); $this->actionAdd($actionDownload); $this->actionAdd(new Am_Grid_Action_Group_Delete()); $this->actionAdd(new Am_Grid_Action_LiveEdit('desc')); } protected function initGridFields() { $this->addField(new Am_Grid_Field('name', ___('Name'), true)); $this->addField(new Am_Grid_Field('desc', ___('Description'), true)); parent::initGridFields(); } public function createForm() { $form = new Am_Form_Admin(); $form->setAttribute('enctype', 'multipart/form-data'); $file = $form->addElement('file', 'upload[]') ->setLabel(___('File')) ->setAttribute('class', 'styled'); $file->addRule('required'); $form->addText('desc', array('class' => 'el-wide')) ->setLabel(___('Description')); $form->addHidden('prefix')->setValue($this->prefix); return $form; } } abstract class Am_Grid_Editable_AffBannersAbstract extends Am_Grid_Editable { protected $affBannerType = null; protected $permissionId = Bootstrap_Aff::ADMIN_PERM_ID; public function __construct(Am_Mvc_Request $request, Am_View $view) { $id = explode('_', get_class($this)); $id = strtolower(array_pop($id)); parent::__construct('_' . $id, $this->getGridTitle(), $this->createDs(), $request, $view); } abstract protected function getGridTitle(); protected function initGridFields() { $this->addField(new Am_Grid_Field('title', ___('Title'), true, '', null, '25%')); $this->addField(new Am_Grid_Field('url', ___('URL'), true, '', null, '35%')); $this->addField(new Am_Grid_Field('category', ___('Category'), true)); $this->addField(new Am_Grid_Field('available', ___('Available'), false))->setRenderFunction(array($this, 'renderUGroup')); $this->addField(new Am_Grid_Field_IsDisabled()); parent::initGridFields(); } public function initActions() { parent::initActions(); $this->actionAdd(new Am_Grid_Action_Sort_AffBanners()); } protected function createDs() { $query = new Am_Query(Am_Di::getInstance()->affBannerTable); $query->addWhere('type=?', $this->affBannerType); $query->setOrder('sort_order'); return $query; } abstract protected function _initForm($form); function createForm() { $form = new Am_Form_Admin; $text = $form->addElement('text', 'title', array('class' => 'el-wide')) ->setLabel(___('Title')); $text->addRule('required'); $url = $form->addElement('text', 'url', array('class' => 'el-wide')) ->setLabel(___('Redirect URL')); $url->addRule('required'); $form->addElement('textarea', 'desc', array('rows' => 10, 'class' => 'el-wide')) ->setLabel(___('Description')); $form->addElement('hidden', 'type') ->setValue($this->affBannerType); $this->_initForm($form); $fs = $form->addAdvFieldset('aff-adv') ->setLabel(___('Advanced')); $catoptions = array_filter(Am_Di::getInstance()->affBannerTable->getCategories()); $catoptions = array_merge(array('' => ___('-- Without A Category --')), $catoptions); $fs->addSelect('category', array(), array('intrinsic_validation' => false, 'options' => $catoptions)) ->setLabel('Display Category'); $label_add_category = ___('add category'); $label_title_error = ___('Enter title for your new category'); $fs->addScript() ->setScript(<< $label_add_category")); jQuery("select[name='category']").change(function(){ jQuery(this).toggle(jQuery(this).find('option').length > 1); }).change(); jQuery(document).on('click',"a#add-category", function(){ var ret = prompt("$label_title_error", ""); if (!ret) return; var \$sel = jQuery("select#category").append( jQuery("").val(ret).html(ret)); \$sel.val(ret).change(); }); }) CUT ); $fs->addMagicselect('user_group_id') ->setLabel(___('Available for users from groups') . "\n" . ___('leave it empty in case of you want this item be available for all users')) ->loadOptions($this->getDi()->userGroupTable->getSelectOptions()); return $form; } function valuesFromForm() { $values = parent::valuesFromForm(); $values['user_group_id'] = implode(',', @$values['user_group_id']); if (!isset($values['category']) || !$values['category']) { $values['category'] = null; } return $values; } function valuesToForm() { $values = parent::valuesToForm(); $values['user_group_id'] = explode(',', @$values['user_group_id']); return $values; } function renderUGroup($b) { $res = array(); $options = $this->getDi()->userGroupTable->getSelectOptions(); foreach (explode(',', $b->user_group_id) as $ug_id) { if (isset($options[$ug_id])) $res[] = $options[$ug_id]; } return $this->renderTd($res ? implode(", ", $res) : ___('All')); } } class Am_Grid_Editable_Banners extends Am_Grid_Editable_AffBannersAbstract { protected $affBannerType = AffBanner::TYPE_BANNER; protected function getGridTitle() { return ___('Banners'); } protected function _initForm($form) { $upload_id = $form->addElement(new Am_Form_Element_Upload('upload_id', array(), array('prefix' => 'banners'))) ->setLabel(___('Image')) ->setId('banners-upload_id') ->setAllowedMimeTypes(array( 'image/png', 'image/jpeg', 'image/tiff', 'image/gif', )); $jsOptions = <<setJsOptions($jsOptions); $upload_id->addRule('required'); $size = $form->addElement('group', 'size') ->setLabel(___("Size\nWidth × Height")); $size->setSeparator(' × '); $width = $size->addElement('text', 'width', array('size' => 4)); $height = $size->addElement('text', 'height', array('size' => 4)); } function valuesFromForm() { $values = parent::valuesFromForm(); $values['height'] = $values['size']['height']; $values['width'] = $values['size']['width']; unset($values['size']); return $values; } function valuesToForm() { $values = parent::valuesToForm(); $values['size']['height'] = @$values['height']; $values['size']['width'] = @$values['width']; return $values; } } class Am_Grid_Editable_TextLinks extends Am_Grid_Editable_AffBannersAbstract { protected $affBannerType = AffBanner::TYPE_TEXTLINK; protected function getGridTitle() { return ___('Text Links'); } protected function _initForm($form) {} } class Am_Grid_Editable_Custom extends Am_Grid_Editable_AffBannersAbstract { protected $affBannerType = AffBanner::TYPE_CUSTOM; protected function getGridTitle() { return ___('Custom HTML'); } protected function _initForm($form) { $form->addTextarea('html', array('rows' => 10, 'class' => 'el-wide')) ->setLabel(___("HTML Code\n%url% will be replaced with actual url of affilate link")) ->addRule('required'); } } class Am_Grid_Editable_LightBoxes extends Am_Grid_Editable_AffBannersAbstract { protected $affBannerType = AffBanner::TYPE_LIGHTBOX; protected function getGridTitle() { return ___('Light Boxes'); } protected function _initForm($form) { $upload_id = $form->addElement(new Am_Form_Element_Upload('upload_id', array(), array('prefix' => 'banners'))) ->setLabel(___('Lightbox Thumbnail Image')) ->setId('lightboxes-upload_id') ->setAllowedMimeTypes(array( 'image/png', 'image/jpeg', 'image/tiff', 'image/gif', )); $upload_id->addRule('required'); $upload_big_id = $form->addElement(new Am_Form_Element_Upload('upload_big_id', array(), array('prefix' => 'banners'))) ->setLabel(___('Lightbox Main Image')) ->setId('lightboxes-upload_big_id') ->setAllowedMimeTypes(array( 'image/png', 'image/jpeg', 'image/tiff', 'image/gif', )); $upload_big_id->addRule('required'); } function valuesFromForm() { $values = parent::valuesFromForm(); $values['height'] = $values['size']['height']; $values['width'] = $values['size']['width']; unset($values['size']); return $values; } function valuesToForm() { $values = parent::valuesToForm(); $values['size']['height'] = @$values['height']; $values['size']['width'] = @$values['width']; return $values; } } class Am_Grid_Editable_AffBannersAll extends Am_Grid_Editable { protected $permissionId = Bootstrap_Aff::ADMIN_PERM_ID; public function __construct(Am_Mvc_Request $request, Am_View $view) { $id = explode('_', get_class($this)); $id = strtolower(array_pop($id)); parent::__construct('_' . $id, $this->getGridTitle(), $this->createDs(), $request, $view); } public function initActions() { $this->actionAdd(new Am_Grid_Action_AffBannersAllEdit('edit', ___('Edit'))); $this->actionAdd(new Am_Grid_Action_Delete); $this->actionAdd(new Am_Grid_Action_Sort_AffBanners()); } function renderUGroup($b) { $res = array(); $options = $this->getDi()->userGroupTable->getSelectOptions(); foreach (explode(',', $b->user_group_id) as $ug_id) { if (isset($options[$ug_id])) $res[] = $options[$ug_id]; } return $this->renderTd($res ? implode(", ", $res) : ___('All')); } protected function getGridTitle() { return ___('All Banners'); } protected function initGridFields() { $this->addField(new Am_Grid_Field_Enum('type', ___('Type'), true)) ->setTranslations(array( AffBanner::TYPE_TEXTLINK => ___('Text Link'), AffBanner::TYPE_BANNER => ___('Banner'), AffBanner::TYPE_PAGEPEEL => ___('Page Peel'), AffBanner::TYPE_LIGHTBOX => ___('Light Box'), AffBanner::TYPE_CUSTOM => ___('Custom HTML') )); $this->addField(new Am_Grid_Field('title', ___('Title'), true, '', null, '25%')); $this->addField(new Am_Grid_Field('url', ___('URL'), true, '', null, '35%')); $this->addField(new Am_Grid_Field('category', ___('Category'), true)); $this->addField(new Am_Grid_Field('available', ___('Available'), false))->setRenderFunction(array($this, 'renderUGroup')); $this->addField(new Am_Grid_Field_IsDisabled()); parent::initGridFields(); } protected function createDs() { $query = new Am_Query(Am_Di::getInstance()->affBannerTable); $query->setOrder('sort_order'); return $query; } } class Am_Grid_Editable_AffBannersCategory extends Am_Grid_Editable { protected $permissionId = Bootstrap_Aff::ADMIN_PERM_ID; public function __construct(Am_Mvc_Request $request, Am_View $view) { $id = explode('_', get_class($this)); $id = strtolower(array_pop($id)); parent::__construct('_' . $id, $this->getGridTitle(), $this->createDs(), $request, $view); } public function initActions() { $this->actionAdd(new Am_Grid_Action_LiveEdit('name')); } protected function getGridTitle() { return ___('Banner Categories'); } protected function initGridFields() { $this->addField(new Am_Grid_Field('name', ___('Title'))); parent::initGridFields(); } protected function createDs() { $ret = array(); foreach (Am_Di::getInstance()->affBannerTable->getCategories() as $category) { $cat = new stdClass(); $cat->name = $category; $ret[] = $cat; } return new Am_Grid_DataSource_AffBannerCategory($ret); } } class Am_Grid_DataSource_AffBannerCategory extends Am_Grid_DataSource_Array { public function updateRecord($record, $valuesFromForm) { Am_Di::getInstance()->db->query('UPDATE ?_aff_banner SET category=? WHERE category=?', $valuesFromForm['name'], $record->name); } } class Am_Grid_Action_Upload extends Am_Grid_Action_Abstract { protected $type = self::NORECORD; public function __construct($id = null, $title = null) { $this->title = ___('Upload'); parent::__construct($id, $title); } public function run() { $form = $this->grid->getForm(); $form->setAttribute('target', '_top'); $upload = new Am_Upload(Am_Di::getInstance()); $upload->setPrefix($this->grid->getCompleteRequest()->getParam('prefix')); $upload->loadFromStored(); $ids_before = $this->getUploadIds($upload); if ($form->isSubmitted() && $upload->processSubmit('upload')) { //find currently uploaded file $upload_id = array_pop(array_diff($this->getUploadIds($upload), $ids_before)); $upload = Am_Di::getInstance()->uploadTable->load($upload_id); $upload->desc = $this->grid->getCompleteRequest()->getParam('desc'); $upload->save(); return $this->grid->redirectBack(); } echo $this->renderTitle(); echo $form; } protected function getUploadIds(Am_Upload $upload) { $upload_ids = array(); foreach ($upload->getUploads() as $upload) { $upload_ids[] = $upload->pk(); } return $upload_ids; } } class Am_Grid_Action_AffBannersAllEdit extends Am_Grid_Action_Abstract { protected $privilege = 'edit'; public function __construct($id, $title) { $this->id = $id; $this->title = $title; parent::__construct(); $this->setTarget('_top'); } public function getUrl($record = null, $id = null) { $id = $record->pk(); switch ($record->type) { case AffBanner::TYPE_TEXTLINK: $prefix = 'textlinks'; break; case AffBanner::TYPE_BANNER: $prefix = 'banners'; break; case AffBanner::TYPE_PAGEPEEL: $prefix = 'pagepeel'; break; case AffBanner::TYPE_LIGHTBOX: $prefix = 'lightboxs'; break; case AffBanner::TYPE_CUSTOM: $prefix = 'custom'; break; default: throw new Am_Exception_InternalError(sprintf('Unknown banner type [%s] in %s::%s', $record->type, __CLASS__, __METHOD__)); } $back_url = Am_Html::escape($this->grid->getBackUrl()); return $this->grid->getDi()->url("aff/admin-banners/p/$prefix/index?_{$prefix}_a=edit&_{$prefix}_b=$back_url&_{$prefix}_id=$id", false); } public function run() { } } class Am_Grid_Action_Sort_AffBanners extends Am_Grid_Action_Sort_Abstract { protected function setSortBetween($item, $after, $before) { $this->_simpleSort(Am_Di::getInstance()->affBannerTable, $item, $after, $before); } } class Aff_AdminGeneralLinkController extends Am_Mvc_Controller { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Aff::ADMIN_PERM_ID); } function indexAction() { $form = $this->createForm(); $form->setDataSources(array($this->getRequest())); if ($this->getRequest()->isPost() && $form->validate()) { $v = $form->getValue(); $this->getDi()->config->saveValue('aff.general_link_url', $v['general_link_url']); } echo $form; } function createForm() { $form = new Am_Form_Admin('aff-general-link'); $form->addElement('text', 'general_link_url', array('class' => 'el-wide')) ->setLabel(___("General Affiliate Link Redirect URL\n" . 'It is url of landing page for default affiliate link (which does not related to any banner), ' . 'home page will be used if you keep it empty')) ->setValue($this->getDi()->config->get('aff.general_link_url', '')); $form->addSaveButton(); return $form; } } class Aff_AdminBannersController extends Am_Mvc_Controller_Pages { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Aff::ADMIN_PERM_ID); } public function preDispatch() { parent::preDispatch(); $this->setActiveMenu('affiliates-banners'); } public function initPages() { $this->addPage(array($this, 'createController'), 'general', ___('General Link')) ->addPage('Am_Grid_Editable_Banners', 'banners', ___('Banners')) ->addPage('Am_Grid_Editable_TextLinks', 'textlinks', ___('Text Links')) //->addPage('Am_Grid_Editable_PagePeels', 'pagePeels', ___('Page Peels')) ->addPage('Am_Grid_Editable_LightBoxes', 'lightboxes', ___('Light Boxes')) ->addPage('Am_Grid_Editable_Custom', 'custom', ___('Custom HTML')) ->addPage('Am_Grid_Editable_AffBannersAll', 'all', ___('All Banners')) ->addPage('Am_Grid_Editable_AffBannersCategory', 'category', ___('Banner Categories')) ->addPage('Am_Grid_Editable_Downloads', 'downloads', ___('Marketing Materials')); } public function createController($id, $title, $grid) { return new Aff_AdminGeneralLinkController($grid->getRequest(), $grid->getResponse(), $this->_invokeArgs); } }PK)\44 controllers/MemberController.phpnu[getDi()->auth->requireLogin($this->getDi()->url('aff/member', null, false)); $this->user = $this->getDi()->user; if (!$this->user->is_affiliate) { //throw new Am_Exception_InputError("Sorry, this page is opened for affiliates only"); $this->_redirect('member'); } } function indexAction() { $this->_redirect('aff/aff'); } function statsAction() { class_exists('Am_Report_Standard', true); include_once AM_APPLICATION_PATH . '/aff/library/Reports.php'; if ($this->getDi()->config->get('aff.affiliate_can_view_details') && $detailDate = $this->getFiltered('detailDate')) { if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $detailDate)) throw new Am_Exception_InputError("Wrong date passed"); $c = 0; foreach ($this->getDi()->affCommissionTable->fetchByDate($detailDate, $this->user->user_id) as $c) { $c++; $p = $c->getPayment(); if (!$p) continue; $u = $p->getUser(); $i = $p->getInvoice(); $product = $c->getProduct(); $s = sprintf('%s (%s) – %s%s', $this->escape($u->name_f . ' ' . $u->name_l), ___($product->title), Am_Currency::render($c->amount), ($c->tier ? sprintf(' (%d-tier)', $c->tier+1) : '')); if ($c->record_type == AffCommission::VOID) $s = "
$s (void)
"; echo $s . "
\n"; } if (!$c) echo ___('No commissions on this date'); return; } $rs = new Am_Report_AffStats(); $rs->setAffId($this->user->user_id); $rc = new Am_Report_AffClicks(); $rc->setAffId($this->user->user_id); $rn = new Am_Report_AffSales(); $rn->setAffId($this->user->user_id); $this->view->monthyear = $this->getInt('monthyear', ''); if (!$this->getInt('monthyear')) { $firstDate[] = $this->getDi()->db->selectCell("SELECT MIN(date) FROM ?_aff_commission WHERE aff_id=?d", $this->user->user_id); $firstDate[] = current(explode(' ', $this->getDi()->db->selectCell("SELECT MIN(`time`) FROM ?_aff_click WHERE aff_id=?d", $this->user->user_id))); $rs->setInterval(min($firstDate), 'now')->setQuantity(new Am_Report_Quant_Month()); } else { $ym = $this->getInt('monthyear'); if (!$ym || strlen($ym) != 6) $ym = date('Ym'); $start = mktime(0, 0, 0, substr($ym, 4, 2), 1, substr($ym, 0, 4)); $rs->setInterval(date('Y-m-d 00:00:00', $start), date('Y-m-t 23:59:59', $start))->setQuantity(new Am_Report_Quant_Day()); $this->view->period = array(date('Y-m-d 00:00:00', $start), date('Y-m-t 23:59:59', $start)); } $rc->setInterval($rs->getStart(), $rs->getStop())->setQuantity(clone $rs->getQuantity()); $rn->setInterval($rs->getStart(), $rs->getStop())->setQuantity(clone $rs->getQuantity()); $result = $rs->getReport(); $rc->getReport($result); $rn->getReport($result); $output = new Am_Report_Graph_Line($result); $output->setSize('100%', 300); $this->view->report = $output->render(); /* extract data from report to show it in view */ $rows = array(); $totals = array(); $lines = $result->getLines(); foreach ($result->getPointsWithValues() as $r) { /* @var $r Am_Report_Point */ if ($result->getQuantity()->getId() == 'month') { $hasValue = false; foreach ($lines as $line) { if ($r->getValue($line->getKey())) { $hasValue = true; break; } } $href = $hasValue ? $this->view->overrideUrl(array("monthyear"=>$r->getKey())) : ''; } elseif ($this->getModule()->getConfig('affiliate_can_view_details')) { $href = "javascript: showAffDetails('{$r->getKey()}')"; } else { $href = ""; } $rows[$r->getKey()]['date'] = $r->getLabel(); $rows[$r->getKey()]['date_href'] = $href; foreach ($lines as $i=>$line){ list($start, $stop) = $result->getQuantity()->getStartStop($r->getKey()); $href = $r->getValue($line->getKey()) > 0 ? sprintf("javascript:affDetail('%s', '%s', '%s')", $start, $stop, $r->getLabel()) : null; $rows[$r->getKey()][$line->getKey() . '_href'] = $href; $rows[$r->getKey()][$line->getKey()] = $r->getValue($line->getKey()); @$totals[$line->getKey()] = $totals[$line->getKey()]+$r->getValue($line->getKey()); } } if ($this->getParam('csv')) { $filename = sprintf("aff-stat-%s-%s.csv", $this->user->login, $this->getInt('monthyear') ?: 'full'); return $this->sendReportFile($rows, $filename); } $this->view->canViewDetails = $this->getModule()->getConfig('affiliate_can_view_details'); $this->view->totals = $totals; $this->view->rows = $rows; $this->view->result = $result; $this->view->display('aff/stats.phtml'); } public function exportDetailsAction() { if (!$this->getModule()->getConfig('affiliate_can_view_details')) { throw new Am_Exception_AccessDenied; } $q = new Am_Query($this->getDi()->affCommissionTable); $q->addWhere('t.aff_id=?', $this->user->pk()) ->leftJoin('?_invoice_item', 'ii', 't.invoice_item_id = ii.invoice_item_id') ->leftJoin('?_invoice', 'i', 'ii.invoice_id = i.invoice_id') ->leftJoin('?_user', 'u', 'i.user_id = u.user_id') ->addField("CONCAT(u.name_f, ' ', u.name_l)", 'u_name') ->addField("ii.item_title"); if ($ym = $this->getInt('monthyear', '')) { $start = mktime(0, 0, 0, substr($ym, 4, 2), 1, substr($ym, 0, 4)); $begin = date('Y-m-d 00:00:00', $start); $end = date('Y-m-t 23:59:59', $start); $q->addWhere('date BETWEEN ? AND ?', $begin, $end); } $filename = sprintf("aff-details-%s-%s.csv", $this->user->login, $this->getInt('monthyear') ?: 'full'); $this->sendDetailsReportFile($q->selectAllRecords(), $filename); } public function sendReportFile($rows, $filename) { $delimiter = ','; $data = array(); $data[] = array( ___('Date'), ___('Transactions'), ___('Commission'), ___('Clicks (All)'), ___('Clicks (Unique)') ); foreach ($rows as $r) { $data[] = array( $r['date'], $r['sales'], $r['commission'], $r['clicks_all'], $r['clicks'] ); } foreach ($data as & $r) { $out = ""; foreach ($r as $s) { $out .= ( $out ? $delimiter : "") . amEscapeCsv($s, $delimiter); } $r = $out; } $this->_helper->sendFile->sendData(implode("\r\n", $data), 'text/csv', $filename); } public function sendDetailsReportFile($rows, $filename) { $delimiter = ','; $data = array(); $data[] = array( ___('Date'), ___('User'), ___('Product'), ___('Type'), ___('Amount'), ___('Tier') ); foreach ($rows as $r) { $data[] = array( $r->date, $r->u_name, $r->item_title, $r->record_type, $r->amount, $r->tier ); } foreach ($data as & $r) { $out = ""; foreach ($r as $s) { $out .= ( $out ? $delimiter : "") . amEscapeCsv($s, $delimiter); } $r = $out; } $this->_helper->sendFile->sendData(implode("\r\n", $data), 'text/csv', $filename); } public function payoutInfoAction() { $form = new Am_Form; $form->addCsrf(); $form->setAction($this->getUrl()); $this->getModule()->addPayoutInputs($form); $form->addSubmit('_save', array('value' => ___('Save'))); $form->addDataSource(new Am_Mvc_Request($d = $this->user->toArray())); if ($form->isSubmitted() && $form->validate()) { foreach ($form->getValue() as $k => $v) { if ($k[0] == '_') continue; if ($k == 'aff_payout_type') $this->user->set($k, $v); else $this->user->data()->set($k, $v); } $this->user->update(); } $this->view->form = $form; $this->view->display('aff/payout-info.phtml'); } public function payoutAction() { $query = new Am_Query($this->getDi()->affPayoutDetailTable); $query->leftJoin('?_aff_payout', 'p', 'p.payout_id=t.payout_id'); $query->addField('p.*') ->addWhere('aff_id=?', $this->user->pk()); $this->view->payouts = $query->selectAllRecords(); $this->view->display('aff/payout.phtml'); } public function clicksDetailAction() { $date_from = $this->getFiltered('from'); $date_to = $this->getFiltered('to'); $this->view->clicks = $this->getDi()->affClickTable->fetchByDateInterval($date_from, $date_to, $this->getDi()->auth->getUserId()); $this->view->display('/aff/clicks-detail.phtml'); } public function getKeywordsReport($uid) { $db = $this->getDi()->db; $db->query('DROP TEMPORARY TABLE IF EXISTS ?_aff_keywords_tmp'); $db->query("CREATE TEMPORARY TABLE ?_aff_keywords_tmp ( keyword_id int not null DEFAULT 0, keyword varchar(64) not null DEFAULT '', clicks_count int not null DEFAULT 0, leads_count int not null DEFAULT 0, sales_count int not null DEFAULT 0, sales_amount int not null DEFAULT 0, PRIMARY KEY (`keyword_id`) )"); //clicks $db->query("INSERT into ?_aff_keywords_tmp (keyword_id, clicks_count) SELECT keyword_id, count(*) from ?_aff_click where keyword_id is not null and aff_id = ? group by keyword_id", $uid); //leads $db->query("INSERT into ?_aff_keywords_tmp (keyword_id, leads_count) SELECT keyword_id, cnt from (SELECT keyword_id, count(*) as cnt from ?_aff_lead where keyword_id is not null and aff_id = ? group by keyword_id) s ON DUPLICATE KEY UPDATE leads_count = s.cnt", $uid); //sales_count $db->query("INSERT into ?_aff_keywords_tmp (keyword_id, sales_count) SELECT keyword_id, cnt from (SELECT keyword_id, sum(if(record_type='commission', 1, 0)) as cnt from ?_aff_commission where keyword_id is not null and aff_id = ? group by keyword_id) s ON DUPLICATE KEY UPDATE sales_count = s.cnt", $uid); //sales_amount $db->query("INSERT into ?_aff_keywords_tmp (keyword_id, sales_amount) SELECT keyword_id, cnt from (SELECT keyword_id, sum(if(record_type='commission', amount, -amount)) as cnt from ?_aff_commission where keyword_id is not null and aff_id = ? group by keyword_id) s ON DUPLICATE KEY UPDATE sales_amount = s.cnt", $uid); //keyword $db->query("UPDATE ?_aff_keywords_tmp t set keyword = (SELECT value from ?_aff_keyword s where s.keyword_id = t.keyword_id)"); $res = array(); $q = $db->queryResultOnly("select * from ?_aff_keywords_tmp"); while ($row = $db->fetchRow($q)) { $res[] = json_decode(json_encode($row), FALSE); } return $res; } public function keywordsAction() { $values = $this->getDi()->cacheFunction->call(array($this, 'getKeywordsReport'),array($this->getDi()->auth->getUserId()), array(), 120); $ds = new Am_Grid_DataSource_Array($values); $grid = new Am_Grid_ReadOnly('_aff_keywords', 'Keywords', $ds, $this->getRequest(), $this->getView()); $grid->addField('keyword', ___('Keyword')); $grid->addField('clicks_count', ___('Clicks')); $grid->addField('leads_count', ___('Leads')); $grid->addField('sales_count', ___('Sales')); $grid->addField('sales_amount', ___('Commissions'))->setRenderFunction( function($record){ return "". Am_Currency::render($record->sales_amount).""; } ); $grid->runWithLayout('aff/keywords.phtml'); } }PK)\TMLְ$controllers/AffPayoutsController.phpnu[ array('class' => 'Aff_AffPayoutDetailsController', 'file' => 'aff/controllers/AffPayoutDetailsController.php'), ); protected $_defaultNested = array( 'aff-payout-details' ); public function createTable() { return $this->getDi()->affPayoutTable; } } PK)\i}uu-controllers/AdminCommissionRuleController.phpnu[getDi()->affCommissionRuleTable->getMaxTier(); $next_tier = ++$max_tier; $comm = $this->getDi()->affCommissionRuleRecord; $comm->tier = $next_tier; $comm->type = AffCommissionRule::TYPE_GLOBAL; $comm->sort_order = ($next_tier + 1) * 10000; $comm->comment = ($next_tier + 1) . '-Tier Affiliates Commission'; $comm->save(); $this->grid->redirectBack(); } /** * @return Am_Di */ protected function getDi() { return $this->grid->getDi(); } } class Am_Grid_Action_RemoveLastTier extends Am_Grid_Action_Abstract { protected $type = Am_Grid_Action_Abstract::NORECORD; protected $title = 'Remove Last Tier'; public function run() { $max_tier = $this->getDi()->affCommissionRuleTable->getMaxTier(); if ($max_tier) { $this->getDi()->affCommissionRuleTable->findFirstByTier($max_tier)->delete(); } $this->grid->redirectBack(); } /** * * @return Am_Di */ protected function getDi() { return $this->grid->getDi(); } } class Am_Grid_Action_TestAffCommissionRule extends Am_Grid_Action_Abstract { protected $type = Am_Grid_Action_Abstract::NORECORD; protected $title = 'Test Commission Rules'; protected $cssClass = 'link'; public function run() { $f = $this->createForm(); $f->setDataSources(array($this->grid->getCompleteRequest())); echo $this->renderTitle(); if ($f->isSubmitted() && $f->validate() && $this->process($f)) return; echo $f; } function process(Am_Form $f) { $vars = $f->getValue(); $user = Am_Di::getInstance()->userTable->findFirstByLogin($vars['user']); if (!$user) { list($el) = $f->getElementsByName('user'); $el->setError(___('User %s not found', $vars['user'])); return false; } $aff = Am_Di::getInstance()->userTable->findFirstByLogin($vars['aff']); if (!$aff) { list($el) = $f->getElementsByName('aff'); $el->setError(___('Affiliate %s not found', $vars['user'])); return false; } $couponAff = null; if ($vars['coupon']) { $coupon = Am_DI::getInstance()->couponTable->findFirstByCode($vars['coupon']); if ($coupon && ($coupon->aff_id || $coupon->getBatch()->aff_id)) { $couponAff = Am_Di::getInstance()->userTable->load($coupon->aff_id ? $coupon->aff_id : $coupon->getBatch()->aff_id, false); } } /* @var $invoice Invoice */ $invoice = Am_Di::getInstance()->invoiceTable->createRecord(); $invoice->setUser($user); if ($vars['coupon']) { $invoice->setCouponCode($vars['coupon']); $error = $invoice->validateCoupon(); if ($error) throw new Am_Exception_InputError($error); } $user->aff_id = $aff->pk(); foreach ($vars['product_id'] as $plan_id => $qty) { $p = Am_Di::getInstance()->billingPlanTable->load($plan_id); $pr = $p->getProduct(); $invoice->add($pr, $qty); } $invoice->calculate(); $invoice->setPaysystem($vars['paysys_id'], false); $invoice->invoice_id = '00000'; $invoice->public_id = 'TEST'; $invoice->tm_added = sqlTime('now'); echo "
";
        echo $invoice->render();
        echo
            "\nBilling Terms: " . $invoice->getTerms() .
            "\n".str_repeat("-", 70)."\n";

        $helper = new Am_View_Helper_UserUrl();
        $helper->setView(new Am_View);
        printf("User Ordering the subscription: %d/%s "%s" <%s>\n",
            $helper->userUrl($user->pk()),
            $user->pk(), Am_Html::escape($user->login),
            Am_Html::escape($user->name_f . ' ' . $user->name_l),
            Am_Html::escape($user->email));
        printf("Reffered Affiliate: %d/%s "%s" <%s>\n",
            $helper->userUrl($aff->pk()),
            $aff->pk(),
            Am_Html::escape($aff->login),
            Am_Html::escape($aff->name_f . ' ' . $aff->name_l),
            Am_Html::escape($aff->email));
        if ($couponAff) {
            printf("Affiliate Detected by Coupon (will get commision): %d/%s "%s" <%s>\n",
                $helper->userUrl($couponAff->pk()),
                $couponAff->pk(),
                Am_Html::escape($couponAff->login),
                Am_Html::escape($couponAff->name_f . ' ' . $couponAff->name_l),
                Am_Html::escape($couponAff->email));
        }

        $max_tier = Am_Di::getInstance()->affCommissionRuleTable->getMaxTier();

        //COMMISSION FOR FREE SIGNUP
        if (!(float)$invoice->first_total
            && !(float)$invoice->second_total
            && $vars['is_first']) {

            echo "\nFREE SIGNUP:\n";
            list($item,) = $invoice->getItems();

            echo sprintf("* ITEM: %s\n", Am_Html::escape($item->item_title));
            foreach (Am_Di::getInstance()->affCommissionRuleTable->findRules($invoice, $item, $aff, 0, 0) as $rule)
            {
                echo $rule->render('*   ');
            }

            $to_pay = Am_Di::getInstance()->affCommissionRuleTable->calculate($invoice, $item, $aff, 0, 0);
            echo "* AFFILIATE WILL GET FOR THIS ITEM: " . Am_Currency::render($to_pay) . "\n";
            for ($i=1; $i<=$max_tier; $i++) {
                $to_pay = Am_Di::getInstance()->affCommissionRuleTable->calculate($invoice, $item, $aff, 0, $i, $to_pay);
                $tier = $i+1;
                echo "* $tier-TIER AFFILIATE WILL GET FOR THIS ITEM: " . Am_Currency::render($to_pay) . "\n";
            }
            echo str_repeat("-", 70) . "\n";

        }

        //COMMISSION FOR FIRST PAYMENT
        $price_field = (float)$invoice->first_total ? 'first_total' : 'second_total';
        if ((float)($invoice->$price_field)) {
            echo "\nFIRST PAYMENT ($invoice->currency {$invoice->$price_field}):\n";

            $payment = Am_Di::getInstance()->invoicePaymentTable->createRecord();
            $payment->invoice_id = @$invoice->invoice_id;
            $payment->dattm = sqlTime('now');
            $payment->amount = $invoice->$price_field;
            echo str_repeat("-", 70) . "\n";
            foreach ($invoice->getItems() as $item)
            {
                if (!(float)($item->$price_field)) continue; //do not calculate commission for free items within invoice
                echo sprintf("* ITEM: %s ($invoice->currency {$item->$price_field})\n", Am_Html::escape($item->item_title));
                foreach (Am_Di::getInstance()->affCommissionRuleTable->findRules($invoice, $item, $aff, 1, 0, $payment->dattm) as $rule)
                {
                    echo $rule->render('*   ');
                }
                $to_pay = Am_Di::getInstance()->affCommissionRuleTable->calculate($invoice, $item, $aff, 1, 0, $payment->amount, $payment->dattm);
                echo "* AFFILIATE WILL GET FOR THIS ITEM: " . Am_Currency::render($to_pay) . "\n";
                for ($i=1; $i<=$max_tier; $i++) {
                    $to_pay = Am_Di::getInstance()->affCommissionRuleTable->calculate($invoice, $item, $aff, 1, $i, $to_pay, $payment->dattm);
                    $tier = $i+1;
                    echo "* $tier-TIER AFFILIATE WILL GET FOR THIS ITEM: " . Am_Currency::render($to_pay) . "\n";
                }
                echo str_repeat("-", 70) . "\n";
            }
        }
        //COMMISSION FOR SECOND AND SUBSEQUENT PAYMENTS
        if ((float)$invoice->second_total)
        {
            echo "\nSECOND AND SUBSEQUENT PAYMENTS ($invoice->second_total $invoice->currency):\n";
            $payment = Am_Di::getInstance()->invoicePaymentTable->createRecord();
            $payment->invoice_id = @$invoice->invoice_id;
            $payment->dattm = sqlTime('now');
            $payment->amount = $invoice->second_total;
            echo str_repeat("-", 70) . "\n";
            foreach ($invoice->getItems() as $item)
            {
                if (!(float)$item->second_total) continue; //do not calculate commission for free items within invoice
                echo sprintf("* ITEM:  %s ($item->second_total $invoice->currency)\n", Am_Html::escape($item->item_title));
                foreach (Am_Di::getInstance()->affCommissionRuleTable->findRules($invoice, $item, $aff, 2, 0, $payment->dattm) as $rule)
                {
                    echo $rule->render('*   ');
                }
                $to_pay = Am_Di::getInstance()->affCommissionRuleTable->calculate($invoice, $item, $aff, 2, 0, $payment->amount, $payment->dattm);
                echo "* AFFILIATE WILL GET FOR THIS ITEM: " . Am_Currency::render($to_pay) . "\n";
                for ($i=1; $i<=$max_tier; $i++) {
                    $to_pay = Am_Di::getInstance()->affCommissionRuleTable->calculate($invoice, $item, $aff, 2, $i, $to_pay, $payment->dattm);
                    $tier = $i+1;
                    echo "* $tier-TIER AFFILIATE WILL GET FOR THIS ITEM: " . Am_Currency::render($to_pay) . "\n";
                }
                echo str_repeat("-", 70) . "\n";
            }
        }
        echo "
"; return true; } protected function createForm() { $f = new Am_Form_Admin; $f->addText('user')->setLabel('Enter username of existing user') ->addRule('required', 'This field is required'); $f->addText('aff')->setLabel('Enter username of existing affiliate') ->addRule('required', 'This field is required'); $f->addText('coupon')->setLabel('Enter coupon code or leave field empty'); $f->addCheckbox('is_first')->setLabel('Is first user invoice?'); $f->addElement(new Am_Form_Element_ProductsWithQty('product_id')) ->setLabel(___('Choose products to include into test invoice')) ->loadOptions(Am_Di::getInstance()->billingPlanTable->selectAllSorted()) ->addRule('required'); $f->addSelect('paysys_id') ->setLabel(___('Payment System')) ->loadOptions(Am_Di::getInstance()->paysystemList->getOptions()); $f->addSubmit('', array('value' => 'Test')); $f->addScript()->setScript(<<grid->getVariablesList() as $k) { $kk = $this->grid->getId() . '_' . $k; if ($v = @$_REQUEST[$kk]) $f->addHidden($kk)->setValue($v); } return $f; } } class Am_Grid_Editable_AffCommissionRule extends Am_Grid_Editable { protected $permissionId = Bootstrap_Aff::ADMIN_PERM_ID; public function renderTable() { $url = $this->getDi()->url('admin-setup/aff'); return parent::renderTable() . ___('

For each item in purchase, aMember will look through all rules, from top to bottom. ' . 'If it finds a matching multiplier, it will be remembered. ' . 'If it finds a matching custom rule, it takes commission rates from it. ' . 'If no matching custom rule was found, it uses "Default" commission settings.

' . '

For n-tier affiliates, no rules are used, you can just define percentage of commission earned by previous level.

') . '

' . ___('Check other Affiliate Program Settings') . '

'; } public function __construct(Am_Mvc_Request $request, Am_View $view) { parent::__construct('_affcommconf', ___('Affiliate Commission Rules'), Am_Di::getInstance()->affCommissionRuleTable->createQuery(), $request, $view); $this->setEventId('gridAffCommissionRule'); $this->setRecordTitle('Commission Rule'); $this->addField('comment', 'Comment')->setRenderFunction(array($this, 'renderComment')); $this->addField('sort_order', 'Sort')->setRenderFunction(array($this, 'renderSort')); $this->addField('_commission', 'Commission', false)->setRenderFunction(array($this, 'renderCommission')); $this->addField('_conditions', 'Conditions', false)->setRenderFunction(array($this, 'renderConditions')); $this->actionGet('edit')->setTarget('_top'); $this->actionGet('insert')->setTitle('New Custom %s')->setTarget('_top'); $this->actionAdd(new Am_Grid_Action_AddTier()); if ($this->getDi()->affCommissionRuleTable->getMaxTier()) { $this->actionAdd(new Am_Grid_Action_RemoveLastTier()); } $this->actionAdd(new Am_Grid_Action_TestAffCommissionRule()); $this->setForm(array($this,'createConfigForm')); $this->addCallback(Am_Grid_Editable::CB_VALUES_TO_FORM, array($this, '_valuesToForm')); $this->addCallback(Am_Grid_Editable::CB_VALUES_FROM_FORM, array($this, '_valuesFromForm')); } public function renderSort(AffCommissionRule $rule) { $v = $rule->isGlobal() ? '-' : $rule->sort_order; return $this->renderTd($v); } public function renderCommission(AffCommissionRule $rule, $fieldName) { return $this->renderTd($rule->renderCommission(), false); } public function renderConditions(AffCommissionRule $rule, $fieldName) { return $this->renderTd($rule->renderConditions(), true); } public function renderComment(AffCommissionRule $rule) { if ($rule->isGlobal()) $text = ''.$rule->comment.''; else $text = $this->escape($rule->comment); return "$text\n"; } public function _valuesToForm(& $values, AffCommissionRule $record) { $values['_conditions'] = json_decode(@$values['conditions'], true); foreach ((array)$values['_conditions'] as $k => $v) { $values['_conditions_status'][$k] = 1; //enabled } } public function _valuesFromForm(& $values, AffCommissionRule $record) { $values['free_signup_t'] = '$'; $conditions = array(); foreach ($values['_conditions_status'] as $k => $v) { if ($v) { $conditions[$k] = $values['_conditions'][$k]; } } $this->cleanUpConditions($conditions); if (!empty($conditions)) { $values['conditions'] = json_encode($conditions); } } /** * Remove incomplete conditions * * @param array $conditions */ protected function cleanUpConditions(& $conditions) { foreach ($conditions as $type => $vars) { switch ($type) { case AffCommissionRule::COND_PRODUCT_ID : case AffCommissionRule::COND_PRODUCT_CATEGORY_ID : case AffCommissionRule::COND_AFF_PRODUCT_ID : case AffCommissionRule::COND_AFF_PRODUCT_CATEGORY_ID : if (empty($vars)) unset($conditions[$type]); break; case AffCommissionRule::COND_AFF_SALES_AMOUNT: case AffCommissionRule::COND_AFF_ITEMS_COUNT: case AffCommissionRule::COND_AFF_SALES_COUNT: if (empty($vars['count']) || empty($vars['days'])) unset($conditions[$type]); break; case AffCommissionRule::COND_COUPON : if (($vars['type'] == 'batch' && !$vars['batch_id']) || ($vars['type'] == 'coupon' && !$vars['code'])) unset($conditions[$type]); break; } } } public function createConfigForm(Am_Grid_Editable $grid) { $form = new Am_Form_Admin; $record = $grid->getRecord($grid->getCurrentAction()); if (empty($record->type)) $record->type = null; if (empty($record->tier)) $record->tier = 0; $globalOptions = AffCommissionRule::getTypes(); ($record->type && !isset($globalOptions[$record->type])) && $globalOptions[$record->type] = $record->getTypeTitle(); $cb = $form->addSelect('type')->setLabel('Type')->loadOptions($globalOptions); if ($record->isGlobal()) $cb->toggleFrozen(true); $form->addScript()->setScript(<<X "); }); jQuery(document).on('click',"a.hide-row",function(){ var row = jQuery(this).closest(".row"); var id = row.hide().attr("id"); var val = /row-(.*)/i.exec(id).pop(); jQuery('input[name="_conditions_status[' + val + ']"]').val(0); jQuery("#condition-select option[value='"+val+"']").prop("disabled", false); }); jQuery('#used-type').change(function(){ jQuery('#used-batch_id, #used-code').hide(); switch (jQuery(this).val()) { case 'batch' : jQuery('#used-batch_id').show(); break; case 'coupon' : jQuery('#used-code').show(); break; } }).change() }); CUT ); $comment = $form->addText('comment', array('size' => 40)) ->setLabel('Rule title - for your own reference'); if ($record->isGlobal()) { $comment->toggleFrozen(true); } else { $comment->addRule('required', 'This field is required'); } if (!$record->isGlobal()) $form->addInteger('sort_order') ->setLabel('Sort order - rules with lesser values executed first'); if (!$record->isGlobal()) // add conditions { $set = $form->addFieldset('', array('id'=>'conditions'))->setLabel('Conditions'); $set->addSelect('', array('id' => 'condition-select'))->setLabel('Add Condition')->loadOptions(array( '' => ___('Select Condition...'), ___('User') => array( 'first_time' => ___('First Time Purchase of Product'), 'first_time_payment' => ___('First Time Purchase'), ), ___('Invoice') => array( 'coupon' => ___('By Used Coupon'), 'paysys_id' => ___('By Used Payment System'), 'product_id' => ___('By Product'), 'product_category_id' => ___('By Product Category'), 'not_product_id' => ___('Not Product'), 'not_product_category_id' => ___('Not Product Category'), 'upgrade' => ___('Upgrade Invoice'), ), ___('Affiliate') => array( 'aff_group_id' => ___('By Affiliate Group Id'), 'aff_sales_count' => ___('By Affiliate Sales Count'), 'aff_items_count' => ___('By Affiliate Item Sales Count'), 'aff_sales_amount' => ___('By Affiliate Sales Amount'), 'aff_product_id' => ___('By Affiliate Active Product'), 'aff_product_category_id' => ___('By Affiliate Active Product Category'), ) )); $set->addHidden('_conditions_status[product_id]'); $set->addMagicSelect('_conditions[product_id]', array('id' => 'product_id')) ->setLabel(___("This rule is for particular products\n" . 'if none specified, rule works for all products')) ->loadOptions(Am_Di::getInstance()->productTable->getOptions()); $set->addHidden('_conditions_status[product_category_id]'); $el = $set->addMagicSelect('_conditions[product_category_id]', array('id' => 'product_category_id')) ->setLabel(___("This rule is for particular product categories\n" . "if none specified, rule works for all product categories")); $el->loadOptions(Am_Di::getInstance()->productCategoryTable->getAdminSelectOptions()); $set->addHidden('_conditions_status[not_product_id]'); $set->addMagicSelect('_conditions[not_product_id]', array('id' => 'not_product_id')) ->setLabel(___("Product is not\n" . 'if none specified, rule works for all products')) ->loadOptions(Am_Di::getInstance()->productTable->getOptions()); $set->addHidden('_conditions_status[not_product_category_id]'); $el = $set->addMagicSelect('_conditions[not_product_category_id]', array('id' => 'not_product_category_id')) ->setLabel(___("Product is not included to Category\n" . "if none specified, rule works for all product categories")); $el->loadOptions(Am_Di::getInstance()->productCategoryTable->getAdminSelectOptions()); $set->addHidden('_conditions_status[aff_group_id]'); $el = $set->addMagicSelect('_conditions[aff_group_id]', array('id' => 'aff_group_id')) ->setLabel(___("This rule is for particular affiliate groups\n" . "you can add user groups and assign it to customers in User editing form")); $el->loadOptions(Am_Di::getInstance()->userGroupTable->getSelectOptions()); $set->addHidden('_conditions_status[aff_sales_count]'); $gr = $set->addGroup('_conditions[aff_sales_count]', array('id' => 'aff_sales_count')) ->setLabel(___("Affiliate sales count\n" . "trigger this commission if affiliate made more than ... sales within ... days before the current date\n" . "(only count of new invoices is calculated)" )); $gr->addStatic()->setContent('use only if affiliate referred '); $gr->addInteger('count', array('size'=>4)); $gr->addStatic()->setContent(' invoices within last '); $gr->addInteger('days', array('size'=>4)); $gr->addStatic()->setContent(' days'); $set->addHidden('_conditions_status[aff_items_count]'); $gr = $set->addGroup('_conditions[aff_items_count]', array('id' => 'aff_items_count')) ->setLabel(___("Affiliate items count\n" . "trigger this commission if affiliate made more than ... item sales within ... days before the current date\n" . "(only count of items in new invoices is calculated" )); $gr->addStatic()->setContent('use only if affiliate made '); $gr->addInteger('count', array('size'=>4)); $gr->addStatic()->setContent(' item sales within last '); $gr->addInteger('days', array('size'=>4)); $gr->addStatic()->setContent(' days'); $set->addHidden('_conditions_status[aff_sales_amount]'); $gr = $set->addGroup('_conditions[aff_sales_amount]', array('id' => 'aff_sales_amount')) ->setLabel(___("Affiliate sales amount\n" . "trigger this commission if affiliate made more than ... sales within ... days before the current date\n" . "(only new invoices calculated)" )); $gr->addStatic()->setContent('use only if affiliate made '); $gr->addInteger('count', array('size'=>4)); $gr->addStatic()->setContent(' ' .Am_Currency::getDefault(). ' in total sales amount within last '); $gr->addInteger('days', array('size'=>4)); $gr->addStatic()->setContent(' days'); $set->addHidden('_conditions_status[coupon]'); $gr = $set->addGroup('_conditions[coupon]', array('id' => 'coupon')) ->setLabel(___('Used coupon')); $gr->setSeparator(' '); $gr->addSelect('used') ->loadOptions(array( '1' => 'Used', '0' => "Didn't Use" )); $gr->addSelect('type') ->setId('used-type') ->loadOptions(array( 'any' => ___('Any Coupon'), 'batch' => ___("Coupon From Batch"), 'coupon' => ___("Specific Coupon") )); $gr->addSelect('batch_id') ->setId('used-batch_id') ->loadOptions( $this->getDi()->couponBatchTable->getOptions() ); $gr->addText('code', array('size'=>10)) ->setId('used-code'); $set->addHidden('_conditions_status[paysys_id]'); $set->addMagicSelect('_conditions[paysys_id]', array('id' => 'paysys_id')) ->setLabel(___('This rule is for particular payment system')) ->loadOptions(Am_Di::getInstance()->paysystemList->getOptions()); $set->addHidden('_conditions_status[first_time]'); $set->addStatic('_conditions[first_time]', array('id' => 'first_time')) ->setLabel(___("First Time Purchase of Product")) ->setContent("
"); $set->addHidden('_conditions_status[first_time_payment]'); $set->addSelect('_conditions[first_time_payment]', array('id' => 'first_time_payment')) ->setLabel(___("First Time Purchase")) ->loadOptions(array( 0 => ___('No'), 1 => ___('Yes') )); $set->addHidden('_conditions_status[upgrade]'); $set->addStatic('_conditions[upgrade]', array('id' => 'upgrade')) ->setLabel(___("Upgrade Invoice")) ->setContent("
"); $set->addHidden('_conditions_status[aff_product_id]'); $set->addMagicSelect('_conditions[aff_product_id]', array('id' => 'aff_product_id')) ->setLabel(___("Apply this rule if affiliate has active access to")) ->loadOptions(Am_Di::getInstance()->productTable->getOptions()); $set->addHidden('_conditions_status[aff_product_category_id]'); $el = $set->addMagicSelect('_conditions[aff_product_category_id]', array('id' => 'aff_product_category_id')) ->setLabel(___("Apply this rule if affiliate has active access to")); $el->loadOptions(Am_Di::getInstance()->productCategoryTable->getAdminSelectOptions()); } $set = $form->addFieldset('', array('id' => 'commission'))->setLabel('Commission'); if ($record->tier == 0) { $set->addElement(new Am_Form_Element_AffCommissionSize(null, null, 'first_payment')) ->setLabel(___("Commission for First Payment\ncalculated for first payment in each invoice")); $set->addElement(new Am_Form_Element_AffCommissionSize(null, null, 'recurring')) ->setLabel(___("Commission for Rebills")); $group = $set->addGroup('') ->setLabel(___("Commission for Free Signup\ncalculated for first customer invoice only")); $group->addText('free_signup_c', array('size'=>5)); $group->addStatic()->setContent('  ' . Am_Currency::getDefault()); ;//->addRule('gte', 'Value must be a valid number > 0, or empty (no text)', 0); } else { $set->addText('first_payment_c') ->setLabel(___("Commission\n% of commission received by referred affiliate")); } if (!$record->isGlobal()) { $set = $form->addFieldset('', array('id' => 'multiplier'))->setLabel('Multipier'); $set->addText('multi', array('size' => 5, 'placeholder' => '1.0')) ->setLabel(___("Multiply commission calculated by the following rules\n" . "to number specified in this field. To keep commission untouched, enter 1 or delete this rule")) ;//->addRule('gt', 'Values must be greater than 0.0', 0.0); } return $form; } } class Aff_AdminCommissionRuleController extends Am_Mvc_Controller_Grid { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Aff::ADMIN_PERM_ID); } public function createGrid() { return new Am_Grid_Editable_AffCommissionRule($this->getRequest(), $this->getView()); } }PK)\,8O66controllers/AdminController.phpnu[ array('name_f', 'name_l', 'login'), 'p' => array('title') ); protected function getPlaceholder() { return ___('Filter by User/Product'); } } class Aff_AdminController extends Am_Mvc_Controller { public function checkAdminPermissions(Admin $admin) { return $admin->hasPermission(Bootstrap_Aff::ADMIN_PERM_ID); } function preDispatch() { $this->user_id = $this->getInt('user_id'); if (!$this->user_id && $this->getRequest()->getActionName() != 'autocomplete') throw new Am_Exception_InputError("Wrong URL specified: no member# passed"); $this->view->user_id = $this->user_id; } function subaffTabAction() { $this->setActiveMenu('users-browse'); $ds = new Am_Query($this->getDi()->userTable); $ds = $ds->addField("CONCAT(name_f, ' ', name_l)", 'name') ->addWhere('is_affiliate=?', 1) ->addWhere('t.aff_id=?', $this->user_id) ->addField("SUM(IF(c.record_type = 'void', -1*c.amount, c.amount))", 'comm') ->leftJoin('?_aff_commission', 'c', 't.user_id=c.aff_id'); $grid = new Am_Grid_ReadOnly('_subaff', ___('Subaffiliate'), $ds, $this->getRequest(), $this->getView(), $this->getDi()); $grid->addField(new Am_Grid_Field('login', ___('Username'), true)) ->addDecorator(new Am_Grid_Field_Decorator_Link($this->view->userUrl('{user_id}'), '_top'));; $grid->addField(new Am_Grid_Field('name', ___('Name'), true)); $grid->addField(new Am_Grid_Field('email', ___('E-Mail Address'), true)); $grid->addField(new Am_Grid_Field('comm', ___('Commission'), true, 'right')) ->setGetFunction(array($this, 'getAmount')) ->addDecorator(new Am_Grid_Field_Decorator_Link($this->getDi()->url('aff/admin/comm-tab/user_id/{user_id}', null, false), '_top')); $grid->runWithLayout('admin/user-layout.phtml'); } function payoutTabAction() { $this->setActiveMenu('users-browse'); $ds = new Am_Query($this->getDi()->affPayoutDetailTable); $ds->leftJoin('?_aff_payout', 'p', 'p.payout_id=t.payout_id'); $ds->addField('p.*') ->addWhere('aff_id=?', $this->user_id) ->setOrder('date', 'DESC'); $grid = new Am_Grid_ReadOnly('_d', ___('Payouts'), $ds, $this->_request, $this->view); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $grid->addField(new Am_Grid_Field_Date('date', ___('Payout Date')))->setFormatDate(); $grid->addField(new Am_Grid_Field_Date('thresehold_date', ___('Thresehold Date')))->setFormatDate(); $grid->addField('type', ___('Payout Method')); $grid->addField('amount', ___('Amount'))->setGetFunction(array($this, 'getAmount')); $grid->addField(new Am_Grid_Field_Enum('is_paid', ___('Is Paid?'))) ->setTranslations(array( 0 => ___('No'), 1 => ___('Yes') )); $grid->addField('_action', '', true)->setRenderFunction(array($this, 'renderLink')); $grid->addCallback(Am_Grid_ReadOnly::CB_RENDER_STATIC, array($this, 'renderStatic')); $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'cbGetTrAttribs')); $grid->runWithLayout('admin/user-layout.phtml'); } function cbGetTrAttribs(& $ret, $record) { if ($record->is_paid) { $ret['class'] = isset($ret['class']) ? $ret['class'] . ' disabled' : 'disabled'; } } public function renderLink(Am_Record $obj) { $iconDetail = $this->getDi()->view->icon('view', ___('Details')); return "$iconDetail"; } public function renderStatic(& $out) { $title = ___('Commissions Included to Payout'); $user_id = $this->getParam('user_id'); $out .= << jQuery(document).on('click','.payout-detail-link', function(){ var div = jQuery('
'); div.load(amUrl("/aff/admin/payout-detail/user_id/$user_id/payout_detail_id/") + jQuery(this).data('payout_detail_id'), {}, function(){ div.dialog({ autoOpen: true ,width: 800 ,buttons: {} ,closeOnEscape: true ,title: "$title" ,modal: true, open : function(){ div.ngrid(); } }); }); }) CUT; } function payoutDetailAction() { $hasTiers = $this->getDi()->affCommissionRuleTable->getMaxTier(); $ds = new Am_Query($this->getDi()->affCommissionTable); $ds->leftJoin('?_invoice', 'i', 'i.invoice_id=t.invoice_id'); $ds->leftJoin('?_user', 'u', 'u.user_id=i.user_id'); $ds->leftJoin('?_product', 'p', 't.product_id=p.product_id'); $ds->addField('u.user_id', 'user_id') ->addField('TRIM(REPLACE(CONCAT(u.login, \' (\',u.name_f, \' \',u.name_l,\') #\', u.user_id), \'( )\', \'\'))', 'user_name') ->addField('u.email', 'user_email') ->addField('p.title', 'product_title'); $ds->addWhere('t.aff_id=?', $this->user_id); $ds->addWhere('payout_detail_id=?', $this->getParam('payout_detail_id')); $ds->setOrder('commission_id', 'desc'); $grid = new Am_Grid_ReadOnly('_affcomm', ___('Affiliate Commission'), $ds, $this->_request, $this->view); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $grid->setCountPerPage(10); $userUrl = new Am_View_Helper_UserUrl(); $grid->addField(new Am_Grid_Field_Date('date', ___('Date')))->setFormatDate(); $grid->addField('user_name', ___('User')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{user_id}'), '_top')); $grid->addField('product_title', ___('Product')); $fieldAmount = $grid->addField('amount', ___('Commission'))->setRenderFunction(array($this, 'renderCommAmount')); if ($hasTiers) { $grid->addField('tier', ___('Tier')) ->setRenderFunction(array($this, 'renderTier')); } $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'commCbGetTrAttribs')); $grid->runWithLayout('admin/user-layout.phtml'); } function commTabAction() { $hasTiers = $this->getDi()->affCommissionRuleTable->getMaxTier(); $this->setActiveMenu('users-browse'); $ds = new Am_Query($this->getDi()->affCommissionTable); $ds->leftJoin('?_invoice', 'i', 'i.invoice_id=t.invoice_id'); $ds->addField('i.public_id'); $ds->leftJoin('?_user', 'u', 'u.user_id=i.user_id'); $ds->leftJoin('?_product', 'p', 't.product_id=p.product_id') ->leftJoin('?_aff_payout_detail', 'apd', 't.payout_detail_id=apd.payout_detail_id') ->leftJoin('?_aff_payout', 'ap', 'ap.payout_id=apd.payout_id') ->addField('ap.date', 'payout_date') ->addField('ap.payout_id') ->addField('u.user_id', 'user_id') ->addField('TRIM(REPLACE(CONCAT(u.login, \' (\',u.name_f, \' \',u.name_l,\') #\', u.user_id), \'( )\', \'\'))', 'user_name') ->addField('p.title', 'product_title'); $ds->setOrder('date', 'desc') ->addWhere('t.aff_id=?', $this->getParam('user_id')); $grid = new Am_Grid_Editable('_affcomm', ___('Affiliate Commission'), $ds, $this->_request, $this->view); $grid->setPermissionId(Bootstrap_Aff::ADMIN_PERM_ID); $grid->actionsClear(); $userUrl = new Am_View_Helper_UserUrl(); $grid->addField(new Am_Grid_Field_Date('date', ___('Date')))->setFormatDate(); $grid->addField('user_name', ___('User')) ->addDecorator(new Am_Grid_Field_Decorator_Link($userUrl->userUrl('{user_id}'), '_top')); $grid->addField('product_title', ___('Product')); $grid->addField('invoice_id', ___('Invoice')) ->setGetFunction(array($this, '_getInvoiceNum')) ->addDecorator( new Am_Grid_Field_Decorator_Link( 'admin-user-payments/index/user_id/{user_id}#invoice-{invoice_id}', '_top')); $fieldAmount = $grid->addField('amount', ___('Commission'))->setRenderFunction(array($this, 'renderCommAmount')); $grid->addField('payout_date', ___('Payout')) ->setRenderFunction(array($this, 'renderPayout')); if ($hasTiers) { $grid->addField('tier', ___('Tier')) ->setRenderFunction(array($this, 'renderTier')); } $grid->addCallback(Am_Grid_ReadOnly::CB_TR_ATTRIBS, array($this, 'commCbGetTrAttribs')); $grid->setFilter(new Am_Grid_Filter_AffCommission()); $grid->actionAdd(new Am_Grid_Action_Total())->addField($fieldAmount, "IF(record_type='void', -1*t.%1\$s, t.%1\$s)"); $grid->actionAdd(new Am_Grid_Action_Aff_Void()); $grid->runWithLayout('admin/user-layout.phtml'); } public function commCbGetTrAttribs(& $ret, $record) { if ($record->record_type == AffCommission::VOID) { $ret['class'] = isset($ret['class']) ? $ret['class'] . ' red' : 'red'; } } public function renderPayout(Am_Record $record, $f, $g) { $out = $record->payout_detail_id ? sprintf('%s', $this->getDi()->url('aff/admin-payout/view', array('payout_id'=>$record->payout_id)), amDate($record->payout_date)): '–'; return $g->renderTd($out, false); } public function renderTier(AffCommission $record) { return sprintf('%s', $record->tier ? ($record->tier + 1) . '-Tier' : '–'); } function infoTabAction() { require_once AM_APPLICATION_PATH . '/default/controllers/AdminUsersController.php'; class_exists('Am_Report_Standard', true); include_once AM_APPLICATION_PATH . '/aff/library/Reports.php'; $this->setActiveMenu('users-browse'); $rs = new Am_Report_AffStats(); $rs->setAffId($this->user_id); $rc = new Am_Report_AffClicks(); $rc->setAffId($this->user_id); $rn = new Am_Report_AffSales(); $rn->setAffId($this->user_id); $form = $rs->getForm(); if (!$form->isSubmitted()) { $form->addDataSource(new HTML_QuickForm2_DataSource_Array(array('period' => Am_Interval::PERIOD_LAST_30_DAYS))); } if ($form->isSubmitted() && $form->validate()) { $rs->applyConfigForm($this->_request); } else { $rs->setInterval('-30 days', 'now')->setQuantity(new Am_Report_Quant_Day()); $form->addDataSource(new Am_Mvc_Request(array('start' => $rs->getStart(), 'stop' => $rs->getStop()))); } $rc->setInterval($rs->getStart(), $rs->getStop())->setQuantity(clone $rs->getQuantity()); $rn->setInterval($rs->getStart(), $rs->getStop())->setQuantity(clone $rs->getQuantity()); $result = $rn->getReport(); $rs->getReport($result); $rc->getReport($result); $this->view->form = $form; $this->view->form->setAction($this->_request->getRequestUri()); $output = new Am_Report_Graph_Line($result); $output->setSize('100%', 300); $this->view->report = $output->render(); $this->view->result = $result; $this->view->display('admin/aff/info-tab.phtml'); } function infoTabDetailAction() { $date_from = $this->getFiltered('from'); $date_to = $this->getFiltered('to'); $this->view->commissions = $this->getDi()->affCommissionTable->fetchByDateInterval($date_from, $date_to, $this->user_id); $this->view->clicks = $this->getDi()->affClickTable->fetchByDateInterval($date_from, $date_to, $this->user_id); $this->view->display('admin/aff/info-tab-detail.phtml'); } public function autocompleteAction() { $term = '%' . $this->getParam('term') . '%'; $exclude = $this->getInt('exclude'); if (!$term) return null; $q = new Am_Query($this->getDi()->userTable); $q->addWhere('((t.login LIKE ?) OR (t.email LIKE ?) OR (t.name_f LIKE ?) OR (t.name_l LIKE ?))', $term, $term, $term, $term); if ($exclude) $q->addWhere('user_id<>?', $exclude); $q->addWhere('is_affiliate>?', 0); $qq = $q->query(0, 10); $ret = array(); while ($r = $this->getDi()->db->fetchRow($qq)) { $ret[] = array ( 'label' => sprintf('%s / "%s" <%s>', $r['login'], $r['name_f'] . ' ' . $r['name_l'], $r['email']), 'value' => $r['login'] ); } if ($q->getFoundRows() > 10) $ret[] = array( 'label' => sprintf("... %d more rows found ...", $q->getFoundRows() - 10), 'value' => null, ); $this->ajaxResponse($ret); } function _getInvoiceNum(Am_Record $invoice) { return $invoice->invoice_id . '/' . $invoice->public_id; } public function getAmount($record, $grid, $field) { return Am_Currency::render($record->{$field}); } public function renderCommAmount($record, $field, $grid) { return sprintf('%s', ($record->record_type == AffCommission::VOID ? '− ' : '') . Am_Currency::render($record->amount)); } }PK)\!controllers/ClickJsController.phpnu[getParam('r')); if (is_numeric($id)) { $aff = $this->getDi()->userTable->load($id, false); if ($aff) return $aff; } if (strlen($id)) { $aff = $this->getDi()->userTable->findFirstByLogin($id); if ($aff) return $aff; } return null; } function findKeyword() { if($keyword = $this->getParam('keyword')) { return substr($keyword, 0, Bootstrap_Aff::KEYWORD_MAX_LEN); } return null; } function indexAction(){ if(!Am_Di::getInstance()->config->get('aff.tracking_code')) { $this->log('Click logging disabled in config'); } elseif ($this->aff = $this->findAff()) { $keyword = $this->findKeyword(); $aff_click_id = $this->getDi()->affClickTable->log($this->aff, null, $this->getParam('s'), $this->getModule()->findKeywordId($this->aff->pk(), $keyword)); $this->getModule()->setCookie($this->aff, null, $aff_click_id); $this->log('Click Logged'); } } function log($text){ if (constant('AM_APPLICATION_ENV') != 'debug') return; echo 'console.log("'.$text.'")'; } } PK)\_[$views/public/css/jquery.lightbox.cssnu[/** * jQuery lightBox plugin * This jQuery plugin was inspired and based on Lightbox 2 by Lokesh Dhakar (http://www.huddletogether.com/projects/lightbox2/) * and adapted to me for use like a plugin from jQuery. * @name jquery-lightbox-0.5.css * @author Leandro Vieira Pinho - http://leandrovieira.com * @version 0.5 * @date April 11, 2008 * @category jQuery plugin * @copyright (c) 2008 Leandro Vieira Pinho (leandrovieira.com) * @license CCAttribution-ShareAlike 2.5 Brazil - http://creativecommons.org/licenses/by-sa/2.5/br/deed.en_US * @example Visit http://leandrovieira.com/projects/jquery/lightbox/ for more informations about this jQuery plugin */ #jquery-overlay { position: absolute; top: 0; left: 0; z-index: 90; width: 100%; height: 500px; } #jquery-lightbox { position: absolute; top: 0; left: 0; width: 100%; z-index: 100; text-align: center; line-height: 0; } #jquery-lightbox a img { border: none; } #lightbox-container-image-box { position: relative; background-color: #fff; width: 250px; height: 250px; margin: 0 auto; } #lightbox-container-image { padding: 10px; } #lightbox-loading { position: absolute; top: 40%; left: 0%; height: 25%; width: 100%; text-align: center; line-height: 0; } #lightbox-nav { position: absolute; top: 0; left: 0; height: 100%; width: 100%; z-index: 10; } #lightbox-container-image-box > #lightbox-nav { left: 0; } #lightbox-nav a { outline: none;} #lightbox-nav-btnPrev, #lightbox-nav-btnNext { width: 49%; height: 100%; zoom: 1; display: block; } #lightbox-nav-btnPrev { left: 0; float: left; } #lightbox-nav-btnNext { right: 0; float: right; } #lightbox-container-image-data-box { font: 10px Verdana, Helvetica, sans-serif; background-color: #fff; margin: 0 auto; line-height: 1.4em; overflow: auto; width: 100%; padding: 0 10px 0; } #lightbox-container-image-data { padding: 0 10px; color: #666; } #lightbox-container-image-data #lightbox-image-details { width: 70%; float: left; text-align: left; } #lightbox-image-details-caption { font-weight: bold; } #lightbox-image-details-currentNumber { display: block; clear: left; padding-bottom: 1.0em; } #lightbox-secNav-btnClose { width: 66px; float: right; padding-bottom: 0.7em; }PK)\(=views/public/css/aff.cssnu[.am-aff-banner-preview { color: #666; background: #fff; border: 1px solid #e0e0e0; border-radius: 3px; margin-bottom: 1em; padding: 1em; box-shadow: 0 1px 1px #e0e0e0; overflow: hidden; } .am-aff-banner-preview dt { font-weight: bold; float: left; margin-right: 0.5em; } .am-aff-banner-preview dt:after { content: ':'; } .am-aff-banner-preview .am-aff-banner-preview-preview { margin-bottom: 1em; } .am-aff-banner-preview .am-aff-banner-preview-info-details { margin-bottom: 1em; } @media all and (min-width: 750px) { .am-aff-banner-preview-info { float: left; width: 60%; } .am-aff-banner-preview-preview { float: right; width: 40%; } .am-aff-banner-preview-info-conteiner { padding-right: 1em; } } .am-aff-banner-note { padding: 1em; margin-bottom: 1.5em; background: #e0e0e0; } .am-aff-mm-item-desc { display: block; } ul.am-aff-banner-cat-list li.am-aff-banner-cat-list-item { list-style-type: none; } PK)\"0@@&views/public/img/lightbox-btn-prev.gifnu[GIF89a? |||zzzxxxvvvtttrrrqqqooommmkkkiiieeecccbbb```^^^\\\ZZZXXXVVVTTTSSSQQQOOOMMMKKKIIIGGGBBB@@@!Y,? YY !  9QI;-PJJHF)KNKLLJ5QJ6:B%T6-KAMR4S.0aVD`ʊB ) BAVl`DĄG@pG$< D UD*#%IzL%Ot a"F`d$a04(zD *#I2B ~rDHPb)7WB.8 ʋkQhTm!Cy˃`8~ N 9D_˟O%J5 ;PK)\j'views/public/img/lightbox-btn-close.gifnu[GIF89aBȾ}}}vvvsssqqqnnniiigggdddbbb___]]]ZZZUUUSSSPPPNNNKKKIIIFFF!,B@pH,Ȥrl:ШZD灌lFqrgP<ڊahis//B/GC"C4/1+ D-1/4CclFe B/euB$3/2* B3!B/GD(((,B/$FG#2( ~4 CDE E/(I1Bb4K D 9c !U=#NzL׈(ѓ0VC*r(PsI5ct0CIlq$#E,0Q1 UӧBDDpiBE# PbG`O%Ba5m+ Wa%E0bd (x!Ø,j # 8JXP(S9( ݘ2 aB1 C*H1P1I2f<7R!|a '?D"Ͽ ;PK)\y_,,&views/public/img/lightbox-btn-next.gifnu[GIF89a? ~~~zzzxxxvvvtttpppnnnllljjjhhhfffdddbbb```^^^\\\ZZZXXXVVVTTTRRRPPPNNNMMMKKKIIIGGGEEECCC!S,? SS&" %&'( %)&%#%' .OC6E BIABBE =FMHBFJCC8-IL25D E3 M`dE xRa\x4-0" %!v@`h QE HC&4H)$b.bDxR$CUI< E1+"A 䄐Q a%dEgGjUtI0>"9:H` $ dBZ숛BI|@@Y-' Q82ZnP+N&HP@ZC T@T)u5νËw4^;PK)\Y)0)views/public/img/lightbox-ico-loading.gifnu[GIF89a }}}{{{xxxvvvsssqqqllliiibbb___ZZZXXXUUUNNNKKKDDDAAA???<<<777222000---+++(((&&&###!!! ! NETSCAPE2.0! U, ,+<@<+'?0JTI0 AB.9$Gŵ$ІBP5#ETG!ψMOL>#^ P2Rh&p *d9G8m `f[Œ$)J1GF rЪ+qdcFHƠ$%@ [m ZHReHN9c#FD .2Bp݇(@(`e"pCfDP =QM8~V! U,U.>@9" /JP?  U?M0 $'!5:5 C6U!:EIB5>PPU<=#=PTL5+M'+I=*I>/NMTTA@"GhX&(ȇU0"P(?4`"=Nbta|I`4IAh\4,#BfPxUPD]"+( aĈB"@t : aAX׮Jf =((Ո;@ˍ$%W* C08p8{hrC(U.4teDR‚hD_('̈jȂA%B!t8bo,P^?(|9H* [ @_noPē/_- k@! U, UU #:B?.6 +BMD/ 7NUPB$1IP=>@5><$@M/B0 BCP# $6*" Ng(@9\dAU@@ZD5|ķ.|8BE Y*D$:r8SL"dD!g) @ƊuR Gip{ITŽ%Ij@ZB(r  "e.  8)|bW̄vPEؖ %|jG `i)!UNJ׌hdڄvQ#8 HNt`EvDHD  >H ! U, U6=59NUN6UB?U #$=PUP<5< 1DH6&?F>$:M>D$$&HJ,UB!U'IL/ $;=V4 eq  C!=R TETAEN ͛Ԑ@ȩlC$*P˜,!%GR1YTTp <:@5AFP4@CUn1H@0*pƎ$ yi"T81+ !dJh6$@BaЁM^!Kj4<ܺtH` KQ"1Dw(FG/<ҤGiE8T9jBf D8y4'!! U,U# 9D?' %IUP:$H9U U4A<3>=,…:A/(UB#+KU>׏ 5P =D5 X} q&lT`#BU!`,$@`K}Q8U  /9%$65- , using rev attribute as href */ //load jQuery if needed if (typeof jQuery == "undefined") { var scriptObj = document.createElement("script"); var head=document.getElementsByTagName("head")[0]; head.insertBefore(scriptObj,head.firstChild); scriptObj.onload = amInitLightbox; scriptObj.src = "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"; scriptObj.type = "text/javascript"; } else { amInitLightbox(); } function amInitLightbox() { // Offering a Custom Alias suport - More info: http://docs.jquery.com/Plugins/Authoring#Custom_Alias (function($) { /** * $ is an alias to jQuery object * */ $.fn.lightBox = function(settings) { // Settings to configure the jQuery lightBox plugin how you like settings = jQuery.extend({ // Configuration related to overlay overlayBgColor: '#000', // (string) Background color to overlay; inform a hexadecimal value like: #RRGGBB. Where RR, GG, and BB are the hexadecimal values for the red, green, and blue values of the color. overlayOpacity: 0.8, // (integer) Opacity value to overlay; inform: 0.X. Where X are number from 0 to 9 // Configuration related to navigation fixedNavigation: false, // (boolean) Boolean that informs if the navigation (next and prev button) will be fixed or not in the interface. // Configuration related to images imageLoading: 'img/lightbox-ico-loading.gif', // (string) Path and the name of the loading icon imageBtnPrev: 'img/lightbox-btn-prev.gif', // (string) Path and the name of the prev button image imageBtnNext: 'img/lightbox-btn-next.gif', // (string) Path and the name of the next button image imageBtnClose: 'img/lightbox-btn-close.gif', // (string) Path and the name of the close btn imageBlank: 'img/lightbox-blank.gif', // (string) Path and the name of a blank image (one pixel) // Configuration related to container image box containerBorderSize: 10, // (integer) If you adjust the padding in the CSS for the container, #lightbox-container-image-box, you will need to update this value containerResizeSpeed: 400, // (integer) Specify the resize duration of container image. These number are miliseconds. 400 is default. // Configuration related to texts in caption. For example: Image 2 of 8. You can alter either "Image" and "of" texts. txtImage: 'Image', // (string) Specify text "Image" txtOf: 'of', // (string) Specify text "of" // Configuration related to keyboard navigation keyToClose: 'c', // (string) (c = close) Letter to close the jQuery lightBox interface. Beyond this letter, the letter X and the SCAPE key is used to. keyToPrev: 'p', // (string) (p = previous) Letter to show the previous image keyToNext: 'n', // (string) (n = next) Letter to show the next image. // Don�t alter these variables in any way imageArray: [], activeImage: 0 },settings); // Caching the jQuery object with all elements matched var jQueryMatchedObj = this; // This, in this context, refer to jQuery object /** * Initializing the plugin calling the start function * * @return boolean false */ function _initialize() { _start(this,jQueryMatchedObj); // This, in this context, refer to object (link) which the user have clicked return false; // Avoid the browser following the link } /** * Start the jQuery lightBox plugin * * @param object objClicked The object (link) whick the user have clicked * @param object jQueryMatchedObj The jQuery object with all elements matched */ function _start(objClicked,jQueryMatchedObj) { // Hime some elements to avoid conflict with overlay in IE. These elements appear above the overlay. $('embed, object, select').css({ 'visibility' : 'hidden' }); // Call the function to create the markup structure; style some elements; assign events in some elements. _set_interface(); // Unset total images in imageArray settings.imageArray.length = 0; // Unset image active information settings.activeImage = 0; // We have an image set? Or just an image? Let�s see it. if ( jQueryMatchedObj.length == 1 ) { settings.imageArray.push(new Array(objClicked.getAttribute('href'),objClicked.getAttribute('title'),objClicked.getAttribute('rev'))); } else { // Add an Array (as many as we have), with href and title atributes, inside the Array that storage the images references for ( var i = 0; i < jQueryMatchedObj.length; i++ ) { settings.imageArray.push(new Array(jQueryMatchedObj[i].getAttribute('href'),jQueryMatchedObj[i].getAttribute('title'))); } } while ( settings.imageArray[settings.activeImage][0] != objClicked.getAttribute('href') ) { settings.activeImage++; } // Call the function that prepares image exibition _set_image_to_view(); } /** * Create the jQuery lightBox plugin interface * * The HTML markup will be like that:
* */ function _set_interface() { // Apply the HTML markup into body tag $('body').append('
'); // Get page sizes var arrPageSizes = ___getPageSize(); // Style overlay and show it $('#jquery-overlay').css({ backgroundColor: settings.overlayBgColor, opacity: settings.overlayOpacity, width: arrPageSizes[0], height: arrPageSizes[1] }).fadeIn(); // Get page scroll var arrPageScroll = ___getPageScroll(); // Calculate top and left offset for the jquery-lightbox div object and show it $('#jquery-lightbox').css({ top: arrPageScroll[1] + (arrPageSizes[3] / 10), left: arrPageScroll[0] }).show(); // Assigning click events in elements to close overlay $('#jquery-overlay,#jquery-lightbox').click(function() { _finish(); }); // Assign the _finish function to lightbox-loading-link and lightbox-secNav-btnClose objects $('#lightbox-loading-link,#lightbox-secNav-btnClose').click(function() { _finish(); return false; }); // If window was resized, calculate the new overlay dimensions $(window).resize(function() { // Get page sizes var arrPageSizes = ___getPageSize(); // Style overlay and show it $('#jquery-overlay').css({ width: arrPageSizes[0], height: arrPageSizes[1] }); // Get page scroll var arrPageScroll = ___getPageScroll(); // Calculate top and left offset for the jquery-lightbox div object and show it $('#jquery-lightbox').css({ top: arrPageScroll[1] + (arrPageSizes[3] / 10), left: arrPageScroll[0] }); }); } /** * Prepares image exibition; doing a image�s preloader to calculate it�s size * */ function _set_image_to_view() { // show the loading // Show the loading $('#lightbox-loading').show(); if ( settings.fixedNavigation ) { $('#lightbox-image,#lightbox-container-image-data-box,#lightbox-image-details-currentNumber').hide(); } else { // Hide some elements $('#lightbox-image,#lightbox-nav,#lightbox-nav-btnPrev,#lightbox-nav-btnNext,#lightbox-container-image-data-box,#lightbox-image-details-currentNumber').hide(); } // Image preload process var objImagePreloader = new Image(); objImagePreloader.onload = function() { $('#lightbox-image').attr('src',settings.imageArray[settings.activeImage][0]). wrap($('').attr('href', settings.imageArray[settings.activeImage][2])); // Perfomance an effect in the image container resizing it _resize_container_image_box(objImagePreloader.width,objImagePreloader.height); // clear onLoad, IE behaves irratically with animated gifs otherwise objImagePreloader.onload=function(){}; }; objImagePreloader.src = settings.imageArray[settings.activeImage][0]; }; /** * Perfomance an effect in the image container resizing it * * @param integer intImageWidth The image�s width that will be showed * @param integer intImageHeight The image�s height that will be showed */ function _resize_container_image_box(intImageWidth,intImageHeight) { // Get current width and height var intCurrentWidth = $('#lightbox-container-image-box').width(); var intCurrentHeight = $('#lightbox-container-image-box').height(); // Get the width and height of the selected image plus the padding var intWidth = (intImageWidth + (settings.containerBorderSize * 2)); // Plus the image�s width and the left and right padding value var intHeight = (intImageHeight + (settings.containerBorderSize * 2)); // Plus the image�s height and the left and right padding value // Diferences var intDiffW = intCurrentWidth - intWidth; var intDiffH = intCurrentHeight - intHeight; // Perfomance the effect $('#lightbox-container-image-box').animate({ width: intWidth, height: intHeight },settings.containerResizeSpeed,function() { _show_image(); }); if ( ( intDiffW == 0 ) && ( intDiffH == 0 ) ) { if ( $.browser.msie ) { ___pause(250); } else { ___pause(100); } } $('#lightbox-container-image-data-box').css({ width: intImageWidth }); $('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css({ height: intImageHeight + (settings.containerBorderSize * 2) }); }; /** * Show the prepared image * */ function _show_image() { $('#lightbox-loading').hide(); $('#lightbox-image').fadeIn(function() { _show_image_data(); _set_navigation(); }); _preload_neighbor_images(); }; /** * Show the image information * */ function _show_image_data() { $('#lightbox-container-image-data-box').slideDown('fast'); $('#lightbox-image-details-caption').hide(); if ( settings.imageArray[settings.activeImage][1] ) { $('#lightbox-image-details-caption').html( $('').attr('href', settings.imageArray[settings.activeImage][2]). append(settings.imageArray[settings.activeImage][1]) ).show(); } // If we have a image set, display 'Image X of X' if ( settings.imageArray.length > 1 ) { $('#lightbox-image-details-currentNumber').html(settings.txtImage + ' ' + ( settings.activeImage + 1 ) + ' ' + settings.txtOf + ' ' + settings.imageArray.length).show(); } } /** * Display the button navigations * */ function _set_navigation() { return; $('#lightbox-nav').show(); // Instead to define this configuration in CSS file, we define here. And it�s need to IE. Just. $('#lightbox-nav-btnPrev,#lightbox-nav-btnNext').css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' }); // Show the prev button, if not the first image in set if ( settings.activeImage != 0 ) { if ( settings.fixedNavigation ) { $('#lightbox-nav-btnPrev').css({ 'background' : 'url(' + settings.imageBtnPrev + ') left 15% no-repeat' }) .unbind() .bind('click',function() { settings.activeImage = settings.activeImage - 1; _set_image_to_view(); return false; }); } else { // Show the images button for Next buttons $('#lightbox-nav-btnPrev').unbind().hover(function() { $(this).css({ 'background' : 'url(' + settings.imageBtnPrev + ') left 15% no-repeat' }); },function() { $(this).css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' }); }).show().bind('click',function() { settings.activeImage = settings.activeImage - 1; _set_image_to_view(); return false; }); } } // Show the next button, if not the last image in set if ( settings.activeImage != ( settings.imageArray.length -1 ) ) { if ( settings.fixedNavigation ) { $('#lightbox-nav-btnNext').css({ 'background' : 'url(' + settings.imageBtnNext + ') right 15% no-repeat' }) .unbind() .bind('click',function() { settings.activeImage = settings.activeImage + 1; _set_image_to_view(); return false; }); } else { // Show the images button for Next buttons $('#lightbox-nav-btnNext').unbind().hover(function() { $(this).css({ 'background' : 'url(' + settings.imageBtnNext + ') right 15% no-repeat' }); },function() { $(this).css({ 'background' : 'transparent url(' + settings.imageBlank + ') no-repeat' }); }).show().bind('click',function() { settings.activeImage = settings.activeImage + 1; _set_image_to_view(); return false; }); } } // Enable keyboard navigation _enable_keyboard_navigation(); } /** * Enable a support to keyboard navigation * */ function _enable_keyboard_navigation() { $(document).keydown(function(objEvent) { _keyboard_action(objEvent); }); } /** * Disable the support to keyboard navigation * */ function _disable_keyboard_navigation() { $(document).unbind(); } /** * Perform the keyboard actions * */ function _keyboard_action(objEvent) { // To ie if ( objEvent == null ) { keycode = event.keyCode; escapeKey = 27; // To Mozilla } else { keycode = objEvent.keyCode; escapeKey = objEvent.DOM_VK_ESCAPE; } // Get the key in lower case form key = String.fromCharCode(keycode).toLowerCase(); // Verify the keys to close the ligthBox if ( ( key == settings.keyToClose ) || ( key == 'x' ) || ( keycode == escapeKey ) ) { _finish(); } // Verify the key to show the previous image if ( ( key == settings.keyToPrev ) || ( keycode == 37 ) ) { // If we�re not showing the first image, call the previous if ( settings.activeImage != 0 ) { settings.activeImage = settings.activeImage - 1; _set_image_to_view(); _disable_keyboard_navigation(); } } // Verify the key to show the next image if ( ( key == settings.keyToNext ) || ( keycode == 39 ) ) { // If we�re not showing the last image, call the next if ( settings.activeImage != ( settings.imageArray.length - 1 ) ) { settings.activeImage = settings.activeImage + 1; _set_image_to_view(); _disable_keyboard_navigation(); } } } /** * Preload prev and next images being showed * */ function _preload_neighbor_images() { if ( (settings.imageArray.length -1) > settings.activeImage ) { objNext = new Image(); objNext.src = settings.imageArray[settings.activeImage + 1][0]; } if ( settings.activeImage > 0 ) { objPrev = new Image(); objPrev.src = settings.imageArray[settings.activeImage -1][0]; } } /** * Remove jQuery lightBox plugin HTML markup * */ function _finish() { $('#jquery-lightbox').remove(); $('#jquery-overlay').fadeOut(function() { $('#jquery-overlay').remove(); }); // Show some elements to avoid conflict with overlay in IE. These elements appear above the overlay. $('embed, object, select').css({ 'visibility' : 'visible' }); } /** / THIRD FUNCTION * getPageSize() by quirksmode.com * * @return Array Return an array with page width, height and window width, height */ function ___getPageSize() { var xScroll, yScroll; if (window.innerHeight && window.scrollMaxY) { xScroll = window.innerWidth + window.scrollMaxX; yScroll = window.innerHeight + window.scrollMaxY; } else if (document.body.scrollHeight > document.body.offsetHeight){ // all but Explorer Mac xScroll = document.body.scrollWidth; yScroll = document.body.scrollHeight; } else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari xScroll = document.body.offsetWidth; yScroll = document.body.offsetHeight; } var windowWidth, windowHeight; if (self.innerHeight) { // all except Explorer if(document.documentElement.clientWidth){ windowWidth = document.documentElement.clientWidth; } else { windowWidth = self.innerWidth; } windowHeight = self.innerHeight; } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode windowWidth = document.documentElement.clientWidth; windowHeight = document.documentElement.clientHeight; } else if (document.body) { // other Explorers windowWidth = document.body.clientWidth; windowHeight = document.body.clientHeight; } // for small pages with total height less then height of the viewport if(yScroll < windowHeight){ pageHeight = windowHeight; } else { pageHeight = yScroll; } // for small pages with total width less then width of the viewport if(xScroll < windowWidth){ pageWidth = xScroll; } else { pageWidth = windowWidth; } arrayPageSize = new Array(pageWidth,pageHeight,windowWidth,windowHeight); return arrayPageSize; }; /** / THIRD FUNCTION * getPageScroll() by quirksmode.com * * @return Array Return an array with x,y page scroll values. */ function ___getPageScroll() { var xScroll, yScroll; if (self.pageYOffset) { yScroll = self.pageYOffset; xScroll = self.pageXOffset; } else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict yScroll = document.documentElement.scrollTop; xScroll = document.documentElement.scrollLeft; } else if (document.body) {// all other Explorers yScroll = document.body.scrollTop; xScroll = document.body.scrollLeft; } arrayPageScroll = new Array(xScroll,yScroll); return arrayPageScroll; }; /** * Stop the code execution from a escified time in milisecond * */ function ___pause(ms) { var date = new Date(); curDate = null; do { var curDate = new Date(); } while ( curDate - date < ms); }; // Return the jQuery object for chaining. The unbind method is used to avoid click conflict when the plugin is called more than once return this.unbind('click').click(_initialize); }; })(jQuery); // Call and execute the function immediately passing the jQuery object } PK)\Ga%views/admin/aff/info-tab-detail.phtmlnu[

getPayment(); if ($p) $invoice = $p->getInvoice(); if ($p) $user = $di->userTable->load($p->user_id); printf("\n", $i++%2 ? ' class="odd grid-row"' : ' class="grid-row"', Am_Currency::render($c->amount), $c->tier ? ($c->tier+1) . '-Tier' : '–' , $c->record_type, $c->invoice_payment_id, $c->receipt_id, $user ? sprintf('%s : "%s" <%s>', $this->escape($user->login), $this->escape($user->name_f . " " . $user->name_l), $this->escape($user->email)): "-", $c->product_id, $this->url('admin-products', array('_product_a'=>'edit','_product_id'=>$c->product_id)), $this->escape($c->product_title) ); endforeach; ?>
%s%s%s%s/%s %s#%d - %s

\n", amDateTime($c->time), $this->escape($c->remote_addr), $this->escape($c->referer), $this->escape($c->referer) ); endforeach; ?>
%s%s %s
PK)\=T*views/admin/aff/widget/top-affiliate.phtmlnu[

·

·

PK)\嵎N N views/admin/aff/info-tab.phtmlnu[setLayout('admin/user-layout.phtml'); $title = ___('Affiliate Information'); $this->enableReports(); ?>

getLines(); /* @var $quant Am_Report_Quant_Date */ $quant = $result->getQuantity(); foreach ($result->getPoints() as $point): /* @var $point Am_Report_Point */ print ""; printf(" \n", $point->getLabel()); foreach ($lines as $line) { list($start, $stop) = $quant->getStartStop($point->getKey()); $href = sprintf("\n", $start, $stop, $point->getLabel(), '%s'); $nohref = ''; printf($point->getValue($line->getKey()) ? $href : $nohref, !$point->getValue($line->getKey()) ? '–' : (($line->getKey() == 'commission') ? ($point->getValue($line->getKey()) >= 0 ? Am_Currency::render($point->getValue($line->getKey())) : '- ' . Am_Currency::render(abs($point->getValue($line->getKey())))): $point->getValue($line->getKey()))); } print ""; endforeach; ?>
%s%s%s
PK)\w(views/blocks/admin-calc-commission.phtmlnu[
PK)\`vVV(views/blocks/admin-void-commission.phtmlnu[
PK)\酸 -views/blocks/admin-user-invoice-details.phtmlnu[
comm_items) : ?>
comm_items as $comm_item) : ?>
date) ?> aff_name) ?> product_title) ?> record_type == AffCommission::VOID): ?>− amount) ?> payout_date) : ?> payout_date) ?> is_paid ? ___('yes') : ___('no')) ?> tier ? ___('%d-Tier', $comm_item->tier + 1): '–' ?> is_voided) : ?> record_type == AffCommission::VOID): ?> ()
comm_items || @count($this->comm_items) < $invoice->getPaymentsCount())): ?> (getName())?>, email); ?>)
PK)\sviews/aff/clicks-detail.phtmlnu[
time)) ?> referer) ?>
PK)\,ӿ((views/aff/payout.phtmlnu[setLayout('member/layout.phtml'); echo $this->blocks('aff/top'); ?>
date)?> thresehold_date)?> type) ?> amount)) ?> is_paid ? ___('Yes') : ___('No')) ?>
PK)\9views/aff/keywords.phtmlnu[setLayout('member/layout.phtml'); ?> blocks('aff/top') ?> blocks('aff/keywords/top') ?>

How to use keywords

If you have different sources of traffic and want to know what is better, you should use keywords.

Let's say you have two different pages where you want to promote our site (example.com/page1.html and example.com/page2.html), and you want to know what page generates more sales.

All you need to do is to include special "keyword" parameter in affiliate link, eg.:

  • Your affiliate link: auth->getUser()->login)));?>
  • Link that you should include in page1.html: ?keyword=page1'; ?>
  • Link that you should include in page2.html: ?keyword=page2'; ?>

When user clicks on affiliate link, we will extract "keyword" parameter from affiliate URL and calculate what "keyword" generates more clicks and sales.

PK)\**views/aff/links.phtmlnu[headLink()->appendStylesheet($this->_scriptCss('aff.css')); $this->setLayout('member/layout.phtml'); /* @var $di Am_Di */ ?> blocks('aff/top') ?> blocks('aff/links/top') ?>

_script('aff/_custom-redirect.phtml'); ?> blocks('aff/links/middle') ?>

url('b/' . $this->obfuscate($banner->pk()) . '/' . urlencode($di->user->login),null,true,2); ?> ' ?>
title) ?>
url(array('aff/go/%s?i=%d', urlencode($di->user->login), $banner->pk()),null,true,true) ?>
url) ?>
desc) : ?>
desc) ?>

blocks('aff/links/bottom') ?>PK)\C views/aff/_custom-redirect.phtmlnu[

PK)\Rviews/aff/payout-info.phtmlnu[setLayout('member/layout.phtml'); $this->headLink()->appendStylesheet($this->_scriptCss('aff.css')); echo $this->blocks('aff/top'); echo $form;PK)\ȐfBBviews/aff/stats.phtmlnu[setLayout('member/layout.phtml'); $this->headLink()->appendStylesheet($this->_scriptCss('aff.css')); echo $this->blocks('aff/top'); if ($rows) : $this->enableReports(); ?>

()

$row) : ?> = 0 ? Am_Currency::render($row['commission']) : '- ' . Am_Currency::render(abs($row['commission'])); ?> = 0 ? Am_Currency::render($totals['commission']) : '- ' . Am_Currency::render(abs($totals['commission'])); ?>
%s', $row['date_href'], (strpos($row['date_href'], 'javascript:') === 0 ? 'local' : ''), $this->escape($row['date'])) : $this->escape($row['date']); ?> %s',$row['clicks_href'], $click) : $click ?>
"> | ">
views/aff/clicks-detail.phtmlnu[PK)\,ӿ((@views/aff/payout.phtmlnu[PK)\9Dviews/aff/keywords.phtmlnu[PK)\**Iviews/aff/links.phtmlnu[PK)\C lYviews/aff/_custom-redirect.phtmlnu[PK)\Rp_views/aff/payout-info.phtmlnu[PK)\ȐfBB{`views/aff/stats.phtmlnu[PK77Rr