Array ('self' => true), 'OnChangePaymentType' => Array ('self' => true), 'OnBecomeAffiliate' => Array ('self' => true), ); $this->permMapping = array_merge($this->permMapping, $permissions); } /** * Generate new affiliate code * * @param kEvent $event * @return string */ function generateAffiliateCode(&$event) { // accepts 1 - 36 $number_length = 11; $num_chars = Array( '1'=>'a','2'=>'b','3'=>'c','4'=>'d','5'=>'e','6'=>'f', '7'=>'g','8'=>'h','9'=>'i','10'=>'j','11'=>'k','12'=>'l', '13'=>'m','14'=>'n','15'=>'o','16'=>'p','17'=>'q','18'=>'r', '19'=>'s','20'=>'t','21'=>'u','22'=>'v','23'=>'w','24'=>'x', '25'=>'y','26'=>'z','27'=>'0','28'=>'1','29'=>'2','30'=>'3', '31'=>'4','32'=>'5','33'=>'6','34'=>'7','35'=>'8','36'=>'9'); $ret = ''; for($i=1; $i<=$number_length; $i++) { mt_srand((double)microtime() * 1000000); $num = mt_rand(1,36); $ret .= $num_chars[$num]; } $ret = strtoupper($ret); $idfield = $this->Application->getUnitOption($event->Prefix, 'IDField'); $table = $this->Application->getUnitOption($event->Prefix, 'TableName'); $sql = 'SELECT %s FROM %s WHERE AffiliateCode = %s'; $code_found = $this->Conn->GetOne( sprintf($sql, $idfield, $table, $this->Conn->qstr($ret) ) ); if($code_found) return $this->generateAffiliateCode($event); return $ret; } /** * Creates new affiliate code when new affiliate is created * * @param kEvent $event */ function OnBeforeItemCreate(&$event) { $object =& $event->getObject( Array('skip_autoload'=>true) ); $object->SetDBField('AffiliateCode', $this->generateAffiliateCode($event) ); } /** * Stores affiliate id using method from Config (session or cookie) if correct code is present in url * * @param kEvent $event * @return bool */ function OnStoreAffiliate(&$event) { $event->Init($event->Prefix, '-item'); $object =& $event->getObject( Array('skip_autoload'=>true) ); $affiliate_storage_method = $this->Application->ConfigValue('Comm_AffiliateStorageMethod'); $affiliate = $this->Application->GetVar('affiliate'); if($affiliate) { $object->Load($affiliate, 'AffiliateCode'); } elseif($affiliate_storage_method == 2) { $affiliate_id = $this->Application->GetVar('affiliate_id'); $object->Load($affiliate_id); } if( $object->isLoaded() && ($object->GetDBField('Status') == 1) ) { // user is found with such email $affiliate_user =& $this->Application->recallObject('u.affiliate', null, Array('skip_autoload'=>true) ); $affiliate_user->Load( $object->GetDBField('PortalUserId') ); if($affiliate_user->GetDBField('Status') == 1) { $affiliate_id = $object->GetDBField('AffiliateId'); $this->Application->setVisitField('AffiliateId', $affiliate_id); if($affiliate_storage_method == 1) { $this->Application->StoreVar('affiliate_id', $affiliate_id); // per session } else { // in cookie $this->Application->Session->SetCookie('affiliate_id', $affiliate_id, $this->getCookieExpiration()); } } } } /** * Returns affiliate cookie expiration date * * @return int */ function getCookieExpiration() { $expire = $this->Application->ConfigValue('Comm_AffiliateCookieDuration'); // days return adodb_mktime() + $expire * 24 * 60 * 60; } /** * Calculate what amount is earned by affiliate based on it's affiliate plan & store it * * @param kEvent $event * @author Alex */ function OnOrderApprove(&$event) { $order =& $this->Application->recallObject( $event->getEventParam('Order_PrefixSpecial') ); $affiliate_id = $order->GetDBField('AffiliateId'); if(!$affiliate_id) return false; $object =& $event->getObject( Array('ship_autoload' => true) ); if( $object->Load($affiliate_id) ) { $affiliate_plan =& $this->Application->recallObject('ap', null, Array('skip_autoload'=>true) ); $affiliate_plan->Load( $object->GetDBField('AffiliatePlanId') ); if( $affiliate_plan->isLoaded() ) { $sql = 'SELECT SUM(Quantity) FROM %s WHERE OrderId = %s'; $orderitems_table = $this->Application->getUnitOption('orditems', 'TableName'); $items_sold = $this->Conn->GetOne( sprintf($sql, $orderitems_table, $order->GetID() ) ); $object->SetDBField('AccumulatedAmount', $object->GetDBField('AccumulatedAmount') + $order->GetDBField('TotalAmount') ); $object->SetDBField('ItemsSold', $object->GetDBField('ItemsSold') + $items_sold); switch( $affiliate_plan->GetDBField('PlanType') ) { case 1: // by amount $value = $object->GetDBField('AccumulatedAmount'); break; case 2: // by items sold (count) $value = $object->GetDBField('ItemsSold'); break; } $apb_table = $this->Application->getUnitOption('apbrackets', 'TableName'); $sql = 'SELECT Percent FROM %1$s WHERE (%2$s >= FromAmount) AND ( (%2$s <= ToAmount) OR (ToAmount = -1) ) AND (AffiliatePlanId = %3$s)'; $commission_percent = $this->Conn->GetOne( sprintf($sql, $apb_table, $this->Conn->qstr($value), $affiliate_plan->GetID() ) ); // process only orders of current affiliate from period start to this order date $period_ends = $order->GetDBField('OrderDate'); $period_starts = $this->getPeriodStartTS( $period_ends, $affiliate_plan->GetDBField('ResetInterval') ); $sql = 'SELECT AffiliateCommission, (SubTotal+ShippingCost+VAT) AS TotalAmount, OrderId FROM '.$order->TableName.' WHERE OrderDate >= %s AND OrderDate <= %s'; $amount_to_pay_before = 0; $amount_to_pay_after = 0; $order_update_sql = 'UPDATE '.$order->TableName.' SET AffiliateCommission = %s WHERE '.$order->IDField.' = %s'; $orders = $this->Conn->Query( sprintf($sql, $period_starts, $period_ends), 'OrderId' ); if($orders) { foreach($orders as $order_id => $order_data) { $amount_to_pay_before += $order_data['AffiliateCommission']; $commission = $order_data['TotalAmount'] * ($commission_percent / 100); $this->Conn->Query( sprintf($order_update_sql, $this->Conn->qstr($commission), $order_id) ); $amount_to_pay_after += $commission; } } $object->SetDBField('AmountToPay', $object->GetDBField('AmountToPay') - $amount_to_pay_before + $amount_to_pay_after ); $object->SetDBField('LastOrderDate_date', $order->GetDBField('OrderDate_date') ); $object->SetDBField('LastOrderDate_time', $order->GetDBField('OrderDate_time') ); $object->Update(); $order->SetDBField('AffiliateCommission', $commission); // set last commission to this order, because ApproveEvent was called for him } } } function OnCheckAffiliateAgreement(&$event) { $user_object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true)); $items_info = $this->Application->GetVar('u'); if($items_info) { list($id,$field_values) = each($items_info); $user_object->SetFieldsFromHash($field_values); $user_object->setID($id); $user_object->setLogin(); } $require_affiliate = ($this->Application->GetVar('RegisterAsAffiliate') == 'on'); if($require_affiliate && !$this->Application->GetVar('AgreeToAffiliateTerms') ) { $this->Application->SetVar('MustAgreeToTerms', 1); $event->MasterEvent->status = erFATAL; } if($require_affiliate && !$this->Application->GetVar('SSN') ) { $this->Application->SetVar('SSNRequiredError', 1); $event->MasterEvent->status = erFATAL; } if( ($event->MasterEvent->status == erFATAL) && $items_info ) $user_object->Validate(); } /** * [AFTER HOOK] to u:OnCreate * * @param kEvent $event */ function OnRegisterAsAffiliate(&$event) { if($this->Application->GetVar('RegisterAsAffiliate') != 'on' || $event->MasterEvent->status != erSUCCESS) { return; } $object =& $event->getObject( Array('skip_autoload' => true) ); $sql = 'SELECT AffiliatePlanId FROM '.$this->Application->getUnitOption('ap', 'TableName').' WHERE IsPrimary = 1'; $affiliate_plan = $this->Conn->GetOne($sql); $object->SetDBField('PortalUserId', $this->Application->GetVar('u.current_id')); $object->SetDBField('Status', 2); $object->SetDBField('AffiliatePlanId', $affiliate_plan); $object->SetDBField('SSN', $this->Application->GetVar('SSN')); $object->SetDBField('Comments', $this->Application->GetVar('Comments')); $object->SetDBField('PaymentTypeId', $this->Application->GetVar('PaymentTypeId')); $object->Create(); $email_event_user =& $this->Application->EmailEventUser('AFFILIATE.REGISTER', $this->Application->GetVar('u.current_id')); $email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.REGISTER'); } function OnBecomeAffiliate(&$event) { if(!$this->Application->GetVar('AgreeToAffiliateTerms')) { $this->Application->SetVar('MustAgreeToTerms', 1); $event->status = erFATAL; } if(!$this->Application->GetVar('SSN')) { $this->Application->SetVar('SSNRequiredError', 1); $event->status = erFATAL; } if($event->status == erFATAL) { return; } $object =& $event->getObject( Array('skip_autoload' => true) ); $sql = 'SELECT AffiliatePlanId FROM '.$this->Application->getUnitOption('ap', 'TableName').' WHERE IsPrimary = 1'; $affiliate_plan = $this->Conn->GetOne($sql); $object->SetDBField('PortalUserId', $this->Application->RecallVar('user_id')); $object->SetDBField('Status', 2); $object->SetDBField('AffiliatePlanId', $affiliate_plan); $object->SetDBField('SSN', $this->Application->GetVar('SSN')); $object->SetDBField('Comments', $this->Application->GetVar('Comments')); $object->SetDBField('PaymentTypeId', $this->Application->GetVar('PaymentTypeId')); $object->Create(); if($next_template = $this->Application->GetVar('next_template')) { $event->redirect = $next_template; } $email_event_user =& $this->Application->EmailEventUser('AFFILIATE.REGISTER', $this->Application->RecallVar('user_id')); $email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.REGISTER'); } function OnChangePaymentType(&$event) { $user_id = $this->Application->RecallVar('user_id'); $object =& $event->getObject( Array('skip_autoload' => true) ); $object->Load( Array('PortalUserId' => $user_id) ); $object->SetDBField('Comments', $this->Application->GetVar('Comments')); $object->SetDBField('PaymentTypeId', $this->Application->GetVar('PaymentTypeId')); $object->Update(); $email_event_user =& $this->Application->EmailEventUser('AFFILIATE.PAYMENT.TYPE.CHANGED', $user_id); $email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.PAYMENT.TYPE.CHANGED'); $event->redirect = $this->Application->GetVar('next_template'); $event->status = erSUCCESS; } /** * If new payments made, then send email about that * * @param kEvent $event */ function OnBeforeDeleteFromLive(&$event) { $payment_object =& $this->Application->recallObject('apayments', 'apayments', Array('skip_autoload' => true) ); $id = $event->getEventParam('id'); $ap_table = $this->Application->getUnitOption('apayments', 'TableName'); $sql = 'SELECT AffiliatePaymentId FROM '.$ap_table.' WHERE AffiliateId = '.$id; $live_ids = $this->Conn->GetCol($sql); $sql = 'SELECT AffiliatePaymentId FROM '.$payment_object->TableName.' WHERE AffiliateId = '.$id; $temp_ids = $this->Conn->GetCol($sql); $new_ids = array_diff($temp_ids, $live_ids); foreach($new_ids as $payment_id) { $payment_object->Load($payment_id); $email_event_user =& $this->Application->EmailEventUser('AFFILIATE.PAYMENT', $payment_object->GetDBField('PortalUserId')); $email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.PAYMENT'); } $object =& $event->getObject(); $passed_id = $event->getEventParam('id'); if( $object->GetID() != $passed_id ) { $object->Load($passed_id); } $sql = 'SELECT Status FROM '.$this->Application->getUnitOption( $event->Prefix, 'TableName' ).' WHERE '.$object->IDField.' = '.$object->GetID(); $old_status = $this->Conn->GetOne($sql); if( $old_status == 2 && $object->GetDBField('Status') == 1 ) { $email_event_user =& $this->Application->EmailEventUser('AFFILIATE.REGISTRATION.APPROVED', $object->GetDBField('PortalUserId')); $email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.REGISTRATION.APPROVED'); } } /** * Resets statistics (accumulated amount & items sold) for affiliates based on ResetInterval in their plan * * @param kEvent $event * @author Alex */ function OnResetStatistics(&$event) { $intervals = Array(86400 => 'la_day', 604800 => 'la_week', 2628000 => 'la_month', 7884000 => 'la_quartely', 31536000 => 'la_year'); $affil_table = $this->Application->getUnitOption($event->Prefix, 'TableName'); $ap_table = $this->Application->getUnitOption('ap', 'TableName'); $sql = 'SELECT AffiliateId FROM '.$affil_table.' a LEFT JOIN '.$ap_table.' ap ON a.AffiliatePlanId = ap.AffiliatePlanId'; $base_time = adodb_mktime(); $where_clause = Array(); foreach($intervals as $interval_length => $interval_description) { $start_timestamp = $this->getPeriodStartTS($base_time, $interval_length); $where_clause[] = 'ap.ResetInterval = '.$interval_length.' AND LastOrderDate < '.$start_timestamp; } $sql .= ' WHERE ('.implode(') OR (', $where_clause).')'; $affiliate_ids = $this->Conn->GetCol($sql); if ($affiliate_ids && defined('DEBUG_MODE') && DEBUG_MODE && $this->Application->isDebugMode()) { $this->Application->Debugger->appendHTML('Affiliates Pending Totals Reset: '); print_pre($affiliate_ids); } $sql = 'UPDATE '.$affil_table.' SET AccumulatedAmount = 0, ItemsSold = 0, LastOrderDate = %s WHERE AffiliateId IN (%s)'; if($affiliate_ids) $this->Conn->Query( sprintf($sql, $base_time, implode(',', $affiliate_ids) ) ); } /** * Returns calendar period start timestamp based on current timestamp ($base_time) and $period_length * * @param int $base_time * @param int $period_length * @return int * @author Alex */ function getPeriodStartTS($base_time, $period_length) { switch($period_length) { case 86400: // day $start_timestamp = adodb_mktime(0,0,0, adodb_date('m', $base_time), adodb_date('d', $base_time), adodb_date('Y', $base_time) ); break; case 604800: // week $day_seconds = 86400; $first_week_day = $this->Application->ConfigValue('FirstDayOfWeek'); $morning = adodb_mktime(0,0,0, adodb_date('m', $base_time), adodb_date('d', $base_time), adodb_date('Y', $base_time) ); $week_day = adodb_date('w', $morning); if($week_day == $first_week_day) { // if it is already first week day, then don't search for previous week day $day_diff = 0; } else { // this way, because sunday is 0, but not 7 as it should be $day_diff = $week_day != 0 ? $week_day - $first_week_day: 7 - $first_week_day; } $start_timestamp = $morning - $day_diff * $day_seconds; break; case 2628000: // month $start_timestamp = adodb_mktime(0,0,0, adodb_date('m', $base_time), 1, adodb_date('Y', $base_time) ); break; case 7884000: // quartal $first_quartal_month = (ceil( adodb_date('m', $base_time) / 3)-1)*3 + 1; $start_timestamp = adodb_mktime(0,0,0, $first_quartal_month, 1, adodb_date('Y', $base_time) ); break; case 31536000: $start_timestamp = adodb_mktime(0,0,0,1,1, adodb_date('Y', $base_time) ); break; } return $start_timestamp; } function iterateItems(&$event) { if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) { $event->status = erFAIL; return; } $object =& $event->getObject( Array('skip_autoload' => true) ); $ids = $this->StoreSelectedIDs($event); if($ids) { $status_field = array_shift( $this->Application->getUnitOption($event->Prefix,'StatusField') ); foreach($ids as $id) { $object->Load($id); switch ($event->Name) { case 'OnMassApprove': $object->SetDBField($status_field, 1); break; case 'OnMassDecline': $object->SetDBField($status_field, 0); break; case 'OnMassMoveUp': $object->SetDBField('Priority', $object->GetDBField('Priority') + 1); break; case 'OnMassMoveDown': $object->SetDBField('Priority', $object->GetDBField('Priority') - 1); break; } if( $object->Update() ) { switch ($event->Name) { case 'OnMassApprove': $email_event_user =& $this->Application->EmailEventUser('AFFILIATE.REGISTRATION.APPROVED', $object->GetDBField('PortalUserId')); $email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.REGISTRATION.APPROVED'); break; case 'OnMassDecline': $email_event_user =& $this->Application->EmailEventUser('AFFILIATE.REGISTRATION.DENIED', $object->GetDBField('PortalUserId')); $email_event_admin =& $this->Application->EmailEventAdmin('AFFILIATE.REGISTRATION.DENIED'); break; } $event->status=erSUCCESS; $event->redirect_params = Array('opener' => 's'); //stay! } else { $event->status=erFAIL; $event->redirect=false; break; } } } } /** * Checks that user in affiliate record matches current user * (non permission-based) * * @param kEvent $event * @return bool */ function checkItemStatus(&$event) { if ($this->Application->isAdminUser) { return true; } $object =& $event->getObject(); if (!$object->isLoaded()) { return true; } return $object->GetDBField('PortalUserId') == $this->Application->RecallVar('user_id'); } }