| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Tracks affiliate referrals and commissions.
|
| 7 |
*/
|
| 8 |
|
| 9 |
define ('ERROR_COMMISSION_NOT_NUMBER', 1);
|
| 10 |
define ('ERROR_COMMISSION_CANT_BE_NEGATIVE', 2);
|
| 11 |
define ('ERROR_COMMISSION_PERCENT_OUT_OF_BORDERS', 3);
|
| 12 |
|
| 13 |
define ('PRODUCT_ENABLED_FOR_AFFILIATES', 1);
|
| 14 |
define ('PRODUCT_DISABLED_FOR_AFFILIATES', 0);
|
| 15 |
define ('PRODUCT_DEFAULT_FOR_AFFILIATES', -1);
|
| 16 |
|
| 17 |
/**
|
| 18 |
* Implementation of hook_help().
|
| 19 |
*/
|
| 20 |
function uc_affiliate_help($section = '') {
|
| 21 |
switch ($section) {
|
| 22 |
case 'admin/modules#description':
|
| 23 |
return t('Tracks affiliate referrals and commissions');
|
| 24 |
break;
|
| 25 |
case 'admin/modules/affiliate':
|
| 26 |
return t('Display user hierarchy.');
|
| 27 |
break;
|
| 28 |
}
|
| 29 |
}
|
| 30 |
|
| 31 |
/**
|
| 32 |
* Implementation of hook_theme().
|
| 33 |
*/
|
| 34 |
function uc_affiliate_theme() {
|
| 35 |
return array(
|
| 36 |
'uc_affiliate_product_settings_table' => array(
|
| 37 |
'arguments' => array('element' => NULL),
|
| 38 |
'file' => 'uc_affiliate.pages.inc',
|
| 39 |
)
|
| 40 |
);
|
| 41 |
}
|
| 42 |
|
| 43 |
/**
|
| 44 |
* Implementation of hook_perm().
|
| 45 |
*/
|
| 46 |
function uc_affiliate_perm() {
|
| 47 |
return array('act as affiliate', 'administer affiliates');
|
| 48 |
}
|
| 49 |
|
| 50 |
/**
|
| 51 |
* Implementation of hook_menu().
|
| 52 |
*/
|
| 53 |
function uc_affiliate_menu() {
|
| 54 |
global $user;
|
| 55 |
|
| 56 |
$items['admin/store/affiliate'] = array(
|
| 57 |
'title' => 'Affiliates',
|
| 58 |
'description' => 'Manage site affiliates',
|
| 59 |
'page callback' => 'uc_affiliate_admin',
|
| 60 |
'access arguments' => array('administer affiliates'),
|
| 61 |
'file' => 'uc_affiliate.admin.inc',
|
| 62 |
);
|
| 63 |
$items['admin/store/affiliate/manage'] = array(
|
| 64 |
'title' => 'Affiliates',
|
| 65 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 66 |
);
|
| 67 |
$items['admin/store/affiliate/settings'] = array(
|
| 68 |
'title' => 'Settings',
|
| 69 |
'page callback' => 'drupal_get_form',
|
| 70 |
'page arguments' => array('uc_affiliate_admin_settings'),
|
| 71 |
'access arguments' => array('administer affiliates'),
|
| 72 |
'type' => MENU_LOCAL_TASK,
|
| 73 |
'file' => 'uc_affiliate.admin.inc',
|
| 74 |
'weight' => 10,
|
| 75 |
);
|
| 76 |
$items['admin/store/affiliate/settings/global'] = array(
|
| 77 |
'title' => 'Global',
|
| 78 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 79 |
);
|
| 80 |
$items['admin/store/affiliate/reports'] = array(
|
| 81 |
'title' => 'Reports',
|
| 82 |
'page callback' => 'uc_affiliate_admin_daily_stats',
|
| 83 |
'access arguments' => array('administer affiliates'),
|
| 84 |
'file' => 'uc_affiliate.admin.inc',
|
| 85 |
'type' => MENU_LOCAL_TASK,
|
| 86 |
);
|
| 87 |
$items['admin/store/affiliate/reports/daily'] = array(
|
| 88 |
'title' => 'Daily reports',
|
| 89 |
'type' => MENU_DEFAULT_LOCAL_TASK ,
|
| 90 |
'weight' => -10,
|
| 91 |
);
|
| 92 |
$items['admin/store/affiliate/reports/affiliate'] = array(
|
| 93 |
'title' => 'Affiliate reports',
|
| 94 |
'page callback' => 'uc_affiliate_admin_user_stats',
|
| 95 |
'access arguments' => array('administer affiliates'),
|
| 96 |
'type' => MENU_LOCAL_TASK,
|
| 97 |
'file' => 'uc_affiliate.admin.inc',
|
| 98 |
);
|
| 99 |
|
| 100 |
$items['user/affiliate/autocomplete'] = array(
|
| 101 |
'title' => 'User autocomplete',
|
| 102 |
'page callback' => 'uc_affiliate_autocomplete',
|
| 103 |
'access arguments' => array('administer affiliates'),
|
| 104 |
'type' => MENU_CALLBACK,
|
| 105 |
'file' => 'uc_affiliate.pages.inc',
|
| 106 |
);
|
| 107 |
|
| 108 |
$items['user/%user/affiliate'] = array(
|
| 109 |
'title' => 'Affiliate program',
|
| 110 |
'access callback' => 'uc_affiliate_permissions',
|
| 111 |
'access arguments' => array(1),
|
| 112 |
'page callback' => 'uc_affiliate_dashboard',
|
| 113 |
'page arguments' => array(1),
|
| 114 |
'type' => MENU_LOCAL_TASK,
|
| 115 |
'weight' => -9,
|
| 116 |
'file' => 'uc_affiliate.pages.inc',
|
| 117 |
);
|
| 118 |
$items['user/%user/affiliate/dashboard'] = array(
|
| 119 |
'title' => 'Dashboard',
|
| 120 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 121 |
'weight' => 0,
|
| 122 |
);
|
| 123 |
$items['user/%user/affiliate/reports'] = array(
|
| 124 |
'title' => 'Reports',
|
| 125 |
'access callback' => 'uc_affiliate_permissions',
|
| 126 |
'access arguments' => array(1),
|
| 127 |
'page callback' => 'uc_affiliate_reports',
|
| 128 |
'page arguments' => array(1),
|
| 129 |
'type' => MENU_LOCAL_TASK,
|
| 130 |
'weight' => 1,
|
| 131 |
'file' => 'uc_affiliate.pages.inc',
|
| 132 |
);
|
| 133 |
$items['user/%user/affiliate/links'] = array(
|
| 134 |
'title' => 'Links',
|
| 135 |
'access callback' => 'uc_affiliate_permissions',
|
| 136 |
'access arguments' => array(1),
|
| 137 |
'page callback' => 'drupal_get_form',
|
| 138 |
'page arguments' => array('uc_affiliate_link_generator_form', 1),
|
| 139 |
'type' => MENU_LOCAL_TASK,
|
| 140 |
'weight' => 2,
|
| 141 |
'file' => 'uc_affiliate.pages.inc',
|
| 142 |
);
|
| 143 |
|
| 144 |
/*// Removing Ubercart's "Orders" tab from affiliates
|
| 145 |
$items[] = array(
|
| 146 |
'path' => 'user/'. arg(1),
|
| 147 |
'title' => t('User'),
|
| 148 |
'type' => MENU_LOCAL_TASK || MENU_CREATED_BY_ADMIN,
|
| 149 |
'callback' => 'uc_affiliate_stats',//'uc_affiliate_dashboard',
|
| 150 |
'access' => 0
|
| 151 |
);
|
| 152 |
|
| 153 |
$items[] = array(
|
| 154 |
'path' => 'user/'. arg(1) .'/view',
|
| 155 |
'title' => t('View'),
|
| 156 |
'access' => 0,
|
| 157 |
'type' => MENU_CREATED_BY_ADMIN,
|
| 158 |
'weight' => -10
|
| 159 |
);
|
| 160 |
|
| 161 |
$items[] = array(
|
| 162 |
'path' => 'user/'. arg(1) .'/orders',
|
| 163 |
'title' => t('Orders'),
|
| 164 |
'description' => t('View your order history.'),
|
| 165 |
'callback' => 'uc_order_history',
|
| 166 |
'callback arguments' => array(arg(1)),
|
| 167 |
'access' => 0,
|
| 168 |
'type' => MENU_CREATED_BY_ADMIN,
|
| 169 |
);*/
|
| 170 |
|
| 171 |
$items['node/%node/edit/affiliate'] = array(
|
| 172 |
'title' => 'Affiliate commission',
|
| 173 |
'access callback' => 'uc_affiliate_product_access',
|
| 174 |
'access arguments' => array(1),
|
| 175 |
'page callback' => 'drupal_get_form',
|
| 176 |
'page arguments' => array('uc_affiliate_product_settings_form', 1),
|
| 177 |
'type' => MENU_LOCAL_TASK,
|
| 178 |
'weight' => -9,
|
| 179 |
'file' => 'uc_affiliate.pages.inc',
|
| 180 |
);
|
| 181 |
|
| 182 |
return $items;
|
| 183 |
}
|
| 184 |
|
| 185 |
/**
|
| 186 |
* Access callback for hook_menu().
|
| 187 |
*/
|
| 188 |
function uc_affiliate_permissions($affiliate = NULL) {
|
| 189 |
global $user;
|
| 190 |
|
| 191 |
if (!$affiliate) {
|
| 192 |
$affiliate = $user;
|
| 193 |
}
|
| 194 |
|
| 195 |
return user_access('act as affiliate', $affiliate) && ($user->uid == $affiliate->uid || user_access('administer affiliates'));
|
| 196 |
}
|
| 197 |
|
| 198 |
/**
|
| 199 |
* Checks access of product node.
|
| 200 |
*/
|
| 201 |
function uc_affiliate_product_access($node) {
|
| 202 |
return ($node->type == 'product' && user_access('administer store'));
|
| 203 |
}
|
| 204 |
|
| 205 |
/**
|
| 206 |
* Increment affiliate counts.
|
| 207 |
*/
|
| 208 |
function uc_affiliate_add_count($aff, $visits = 0, $users = 0, $sales = 0, $returns = 0, $commission = 0, $profit = 0) {
|
| 209 |
$time = uc_affiliate_current_time();
|
| 210 |
|
| 211 |
$res = db_fetch_object(db_query('SELECT affid, visits, users, sales, returns, commission, profit, time FROM {uc_affiliate_counts} WHERE affid=%d AND time=%d', $aff, $time));
|
| 212 |
if ($res && $res->time) {
|
| 213 |
db_query('UPDATE {uc_affiliate_counts} SET visits=(visits+%d), users=(users+%d), sales=(sales+%d), returns=(returns+%d), commission=(commission+%f), profit=(profit+%f) WHERE affid=%d AND time=%d', $visits, $users, $sales, $returns, $commission, $profit, $aff, $time);
|
| 214 |
}
|
| 215 |
else {
|
| 216 |
db_query('INSERT {uc_affiliate_counts} (affid, visits, users, sales, returns, commission, profit, time) VALUES (%d, %d, %d, %d, %d, %f, %f, %d)', $aff, $visits, $users, $sales, $returns, $commission, $profit, $time);
|
| 217 |
}
|
| 218 |
}
|
| 219 |
|
| 220 |
/**
|
| 221 |
* Implementation of hook_exit().
|
| 222 |
*/
|
| 223 |
function uc_affiliate_exit($destination = NULL) {
|
| 224 |
// this function sets $_SESSION['affid'] and increments click count
|
| 225 |
uc_affiliate_click();
|
| 226 |
}
|
| 227 |
|
| 228 |
/**
|
| 229 |
* Records affiliate ID in the user session and counts the click.
|
| 230 |
*/
|
| 231 |
function uc_affiliate_click() {
|
| 232 |
if (isset($_REQUEST['a'])) {
|
| 233 |
$affid = (int)$_REQUEST['a'];
|
| 234 |
if ($affid) {
|
| 235 |
// store affiliate id in session and increment click count
|
| 236 |
if (!$_SESSION['affid']) {
|
| 237 |
$_SESSION['affid'] = $affid;
|
| 238 |
uc_affiliate_add_count($affid, 1, 0, 0, 0, 0);
|
| 239 |
}
|
| 240 |
}
|
| 241 |
}
|
| 242 |
}
|
| 243 |
|
| 244 |
/**
|
| 245 |
* Implementation of hook_add_to_cart_data().
|
| 246 |
* Add tracking of which store each product comes from.
|
| 247 |
*/
|
| 248 |
function uc_affiliate_add_to_cart_data($form_values) {
|
| 249 |
if (!empty($_SESSION['affid'])) {
|
| 250 |
return array('affid' => $_SESSION['affid']);
|
| 251 |
}
|
| 252 |
}
|
| 253 |
|
| 254 |
/**
|
| 255 |
* Implementation of hook_order().
|
| 256 |
*/
|
| 257 |
function uc_affiliate_order($op, $order, $status) {
|
| 258 |
switch ($op) {
|
| 259 |
case 'update':
|
| 260 |
if (in_array($status, variable_get('uc_affiliate_commission_order_status', array('completed')))) {
|
| 261 |
uc_affiliate_process_sale($order);
|
| 262 |
}
|
| 263 |
elseif (in_array($status, variable_get('uc_affiliate_commission_return_status', array('canceled')))) {
|
| 264 |
uc_affiliate_process_return($order);
|
| 265 |
}
|
| 266 |
}
|
| 267 |
}
|
| 268 |
|
| 269 |
/**
|
| 270 |
* Helper for hook_order(). Tracks affiliate commissions.
|
| 271 |
*
|
| 272 |
* @param object $order
|
| 273 |
* Order to process.
|
| 274 |
*/
|
| 275 |
function uc_affiliate_process_sale($order) {
|
| 276 |
global $user;
|
| 277 |
|
| 278 |
// This prevents double commissions assigning.
|
| 279 |
$result = db_result(db_query('SELECT COUNT(*) FROM {uc_affiliate_commissions} WHERE order_id = %d ORDER BY commission DESC', $order->order_id));
|
| 280 |
if ($result) {
|
| 281 |
return FALSE;
|
| 282 |
}
|
| 283 |
|
| 284 |
// Order ready for commission assignment
|
| 285 |
$sales = array();
|
| 286 |
|
| 287 |
// Sum the prices of products.
|
| 288 |
foreach ($order->products as $product) {
|
| 289 |
if (isset($product->data['affid']) && $affid = $product->data['affid']) {
|
| 290 |
$sales[$affid][$product->nid]['count'] += $product->qty;
|
| 291 |
$sales[$affid][$product->nid]['price'] += $product->qty * $product->price;
|
| 292 |
}
|
| 293 |
}
|
| 294 |
|
| 295 |
if (!empty($sales)) {
|
| 296 |
$level = 0;
|
| 297 |
// Write commission records.
|
| 298 |
foreach ($sales as $affid => $products) {
|
| 299 |
foreach ($products as $nid => $total) {
|
| 300 |
$commission = uc_affiliate_get_commission($nid, $affid, $total);
|
| 301 |
// Allow other modules to affect on commission (can't use general
|
| 302 |
// invoke because sending amount by reference).
|
| 303 |
foreach (module_implements('uc_affiliate_pre_sale') as $module) {
|
| 304 |
$function = $module .'_uc_affiliate_pre_sale';
|
| 305 |
$function($order, $nid, $affid, $commission);
|
| 306 |
}
|
| 307 |
if ($commission > 0) {
|
| 308 |
$commission_str = uc_affiliate_commission2str(uc_affiliate_get_product_commissions_data($nid, $affid), TRUE);
|
| 309 |
|
| 310 |
$profit = $total['price'] - $commission;
|
| 311 |
|
| 312 |
$note = t('Level @level commission of (@comm_str * @count[@price] = @comm) recorded for affiliate @affiliate', array('@affiliate' => $affid, '@comm' => $commission, '@comm_str' => $commission_str, '@level' => $level, '@count' => $total['count'], '@price' => $total['price']));
|
| 313 |
db_query('INSERT {uc_affiliate_commissions} (order_id, affid, level, commission, commission_notes) VALUES (%d, %d, %d, %f, "%s")', $order->order_id, $affid, $level, $commission, $note);
|
| 314 |
uc_affiliate_add_count($affid, 0, 0, 1, 0, $commission, $profit);
|
| 315 |
uc_order_comment_save($order->order_id, $user->uid, $note);
|
| 316 |
|
| 317 |
// Allow other modules to react on sale.
|
| 318 |
module_invoke_all('uc_affiliate_sale', $order, $nid, $affid, $commission);
|
| 319 |
}
|
| 320 |
}
|
| 321 |
}
|
| 322 |
return TRUE;
|
| 323 |
}
|
| 324 |
return FALSE;
|
| 325 |
}
|
| 326 |
|
| 327 |
/**
|
| 328 |
* Helper for hook_order(). Tracks returns.
|
| 329 |
*
|
| 330 |
* @param object $order
|
| 331 |
* Order to process.
|
| 332 |
*/
|
| 333 |
function uc_affiliate_process_return($order) {
|
| 334 |
// This prevents double returns procesing.
|
| 335 |
$result = db_result(db_query('SELECT COUNT(*) FROM {uc_affiliate_commissions} WHERE order_id = %d AND commission < 0', $order->order_id));
|
| 336 |
if ($result) {
|
| 337 |
return FALSE;
|
| 338 |
}
|
| 339 |
|
| 340 |
$result = db_query('SELECT order_id, affid, level, commission, commission_notes FROM {uc_affiliate_commissions} WHERE order_id = %d AND level = 0 AND commission > 0', $order->order_id);
|
| 341 |
while ($data = db_fetch_object($result)) {
|
| 342 |
$return_amount = -$data->commission;
|
| 343 |
|
| 344 |
// Allow other modules to affect on return amount (can't use general
|
| 345 |
// invoke because sending amount by reference).
|
| 346 |
foreach (module_implements('uc_affiliate_pre_return') as $module) {
|
| 347 |
$function = $module .'_uc_affiliate_pre_return';
|
| 348 |
$function($order, $data->affid, $return_amount);
|
| 349 |
}
|
| 350 |
|
| 351 |
if ($return_amount < 0) {
|
| 352 |
$note = t('Return commissions (@comm) of order @order from affiliate @affiliate', array('@order' => $data->order_id, '@affiliate' => $data->affid, '@comm' => $return_amount));
|
| 353 |
db_query('INSERT {uc_affiliate_commissions} (order_id, affid, level, commission, commission_notes) VALUES (%d, %d, %d, %f, "%s")', $data->order_id, $data->affid, $data->level, $return_amount, $note);
|
| 354 |
uc_order_comment_save($data->order_id, $data->affid, $note);
|
| 355 |
uc_affiliate_add_count($data->affid, 0, 0, 0, 1, $return_amount);
|
| 356 |
|
| 357 |
// Allow other modules to react on return.
|
| 358 |
module_invoke_all('uc_affiliate_return', $order, $data->affid, $return_amount);
|
| 359 |
}
|
| 360 |
}
|
| 361 |
return TRUE;
|
| 362 |
}
|
| 363 |
|
| 364 |
/**
|
| 365 |
* Get array of allowed products for selling through the affiliate network.
|
| 366 |
*
|
| 367 |
* @param $affid
|
| 368 |
* Affiliate ID (default - for all affiliates).
|
| 369 |
* @return
|
| 370 |
* Array of product available for selling to specific affiliate.
|
| 371 |
*/
|
| 372 |
function uc_affiliate_get_affiliate_available_products($affid = NULL) {
|
| 373 |
if (is_object($affid)) {
|
| 374 |
$affid = $affid->uid;
|
| 375 |
}
|
| 376 |
|
| 377 |
// Prepare query.
|
| 378 |
$query = 'SELECT DISTINCT(n.nid), n.title, COALESCE(uap.affid, 0) as "affid", uap.commission, COALESCE(uap.allowed, -1) as "allowed"
|
| 379 |
FROM {uc_products} up
|
| 380 |
LEFT JOIN {node} n ON n.nid = up.nid AND n.vid = up.vid
|
| 381 |
LEFT JOIN {uc_affiliate_products} uap ON up.nid = uap.nid
|
| 382 |
WHERE uap.affid = 0 OR uap.affid IS NULL';
|
| 383 |
if ($affid) {
|
| 384 |
$query .= ' OR uap.affid = %d';
|
| 385 |
}
|
| 386 |
$query .= ' ORDER BY uap.affid';
|
| 387 |
$result = db_query($query, $affid);
|
| 388 |
|
| 389 |
$allowed_by_default = variable_get('uc_affiliate_allow_products_by_default', TRUE);
|
| 390 |
$products = array();
|
| 391 |
while ($product = db_fetch_array($result)) {
|
| 392 |
// We should skip default commission for specific affids, as it is already processed.
|
| 393 |
if ($product['affid'] && $product['allowed'] == PRODUCT_DEFAULT_FOR_AFFILIATES) {
|
| 394 |
continue;
|
| 395 |
}
|
| 396 |
|
| 397 |
if (($product['allowed'] == PRODUCT_DEFAULT_FOR_AFFILIATES && $allowed_by_default) || ($product['allowed'] == PRODUCT_ENABLED_FOR_AFFILIATES)) {
|
| 398 |
$products[$product['nid']] = $product;
|
| 399 |
}
|
| 400 |
else {
|
| 401 |
unset($products[$product['nid']]);
|
| 402 |
}
|
| 403 |
}
|
| 404 |
|
| 405 |
return $products;
|
| 406 |
}
|
| 407 |
|
| 408 |
/**
|
| 409 |
* Check if affiliate can sell a product.
|
| 410 |
* @return
|
| 411 |
* TRUE or FALSE.
|
| 412 |
* @param int $affid
|
| 413 |
* Affilite's UID.
|
| 414 |
* @param int $nid
|
| 415 |
* Product NID.
|
| 416 |
*/
|
| 417 |
function uc_affiliate_is_affiliate_available_product($affid, $nid) {
|
| 418 |
$products = uc_affiliate_get_affiliate_available_products($affid);
|
| 419 |
return isset($products[$nid]);
|
| 420 |
}
|
| 421 |
|
| 422 |
/**
|
| 423 |
* Check affiliate's activity since last 3 months.
|
| 424 |
*/
|
| 425 |
function uc_affiliate_is_affiliate_active($affid) {
|
| 426 |
return db_result(db_query('SELECT COUNT(*) FROM {uc_affiliate_counts} WHERE affid = %d AND time > %d', $affid, strtotime("-30 days")));
|
| 427 |
}
|
| 428 |
|
| 429 |
/**
|
| 430 |
* Returns affiliate commission by given product and price.
|
| 431 |
*
|
| 432 |
* @param int $nid
|
| 433 |
* Product NID.
|
| 434 |
* @param int $affid
|
| 435 |
* Affiliate UID.
|
| 436 |
* @param array $total[optional]
|
| 437 |
* Array with order item info.
|
| 438 |
* @param int $total['count']
|
| 439 |
* Count of products in order item (for currency commissions).
|
| 440 |
* @param int $total['price']
|
| 441 |
* Total price of order item (for percent commissions).
|
| 442 |
* @param object $level[optional]
|
| 443 |
* Referral level.
|
| 444 |
* @return
|
| 445 |
* Commission.
|
| 446 |
*/
|
| 447 |
function uc_affiliate_get_commission($nid, $affid, $total = NULL, $level = 0) {
|
| 448 |
$data = uc_affiliate_get_product_commissions_data($nid, $affid);
|
| 449 |
|
| 450 |
if (!$total) {
|
| 451 |
$product = node_load($nid);
|
| 452 |
$total = array(
|
| 453 |
'count' => 1,
|
| 454 |
'price' => $product->sell_price,
|
| 455 |
);
|
| 456 |
}
|
| 457 |
|
| 458 |
switch ($data['commission'][$level]['type']) {
|
| 459 |
case 'currency':
|
| 460 |
$result = round($total['count'] * $data['commission'][$level]['value'], 3);
|
| 461 |
break;
|
| 462 |
case 'percent':
|
| 463 |
$result = round($total['price'] * ($data['commission'][$level]['value']/100), 3);
|
| 464 |
break;
|
| 465 |
}
|
| 466 |
|
| 467 |
if (variable_get('uc_affiliate_ceil_commission', TRUE)) {
|
| 468 |
$result = ceil($result);
|
| 469 |
}
|
| 470 |
|
| 471 |
return $result;
|
| 472 |
}
|
| 473 |
|
| 474 |
/**
|
| 475 |
* Get product's commissions data.
|
| 476 |
*
|
| 477 |
* @param $nid
|
| 478 |
* ID of product's node.
|
| 479 |
* @param $affid
|
| 480 |
* Optional. Affiliate ID which want to sell this product (default - array of commissions for all affiliates).
|
| 481 |
* @param $as_string
|
| 482 |
* Optional. If TRUE, will be returned string representation of commission structure.
|
| 483 |
*
|
| 484 |
* @return
|
| 485 |
* Array of product's commissions, or FALSE if nothing is specified.
|
| 486 |
*/
|
| 487 |
function uc_affiliate_get_product_commissions_data($nid, $affid = NULL, $options = array('fill_defaults' => TRUE, 'as_string' => FALSE)) {
|
| 488 |
if (is_object($affid)) {
|
| 489 |
$affid = $affid->uid;
|
| 490 |
}
|
| 491 |
|
| 492 |
// Prepare query.
|
| 493 |
$query = 'SELECT uap.*, u.name as username FROM {uc_affiliate_products} uap LEFT JOIN {users} u ON u.uid = uap.affid WHERE (uap.nid = %d)';
|
| 494 |
if ($affid) {
|
| 495 |
$query .= ' AND ((uap.affid = %d)||(uap.affid = 0))';
|
| 496 |
}
|
| 497 |
$query .= ' ORDER BY u.name';
|
| 498 |
$result = db_query($query, $nid, $affid);
|
| 499 |
|
| 500 |
$commissions = array();
|
| 501 |
while ($record = db_fetch_array($result)) {
|
| 502 |
$record['commission'] = unserialize($record['commission']);
|
| 503 |
$commissions[$record['affid']] = $record;
|
| 504 |
}
|
| 505 |
|
| 506 |
// In case when we show commissions table in admin area, we don't need this,
|
| 507 |
// because default values should be shown as blank.
|
| 508 |
if (!isset($options['fill_defaults']) || $options['fill_defaults']) {
|
| 509 |
// Global product settings are always being stored in nid=0.
|
| 510 |
if (isset($commissions[0])) {
|
| 511 |
$global_product_settings = $commissions[0];
|
| 512 |
}
|
| 513 |
else {
|
| 514 |
$global_product_settings = array(
|
| 515 |
'allowed' => variable_get('uc_affiliate_allow_products_by_default', TRUE),
|
| 516 |
);
|
| 517 |
}
|
| 518 |
|
| 519 |
// Fill up product's commission with global commission if it's not set.
|
| 520 |
if (!isset($global_product_settings['commission']) || empty($global_product_settings['commission'])){
|
| 521 |
$global_product_settings['commission'] = variable_get('uc_affiliate_commission', uc_affiliate_default_commission());
|
| 522 |
}
|
| 523 |
|
| 524 |
foreach ($commissions as $key => $commission){
|
| 525 |
// if commission settings is blank, we should load global settings
|
| 526 |
if (empty($commission['commission'])){
|
| 527 |
$commissions[$key]['commission'] = $global_product_settings['commission'];
|
| 528 |
}
|
| 529 |
}
|
| 530 |
}
|
| 531 |
|
| 532 |
// Render as string if needed.
|
| 533 |
if ((!isset($options['as_string']) || $options['as_string']) && !empty($commissions)) {
|
| 534 |
foreach ($commissions as $key => $commission){
|
| 535 |
$commissions[$key] = uc_affiliate_commission2str($commissions[$key]);
|
| 536 |
}
|
| 537 |
}
|
| 538 |
|
| 539 |
// If certain affiliate provided, we should check allowance of the product for this affiliate.
|
| 540 |
if ($affid) {
|
| 541 |
if (uc_affiliate_is_affiliate_available_product($affid, $nid)) {
|
| 542 |
// Fill defaults
|
| 543 |
if (!$commissions[$affid]){
|
| 544 |
$commissions[$affid] = $global_product_settings;
|
| 545 |
}
|
| 546 |
|
| 547 |
$commissions = $commissions[$affid];
|
| 548 |
}
|
| 549 |
else {
|
| 550 |
$commissions = 0;
|
| 551 |
}
|
| 552 |
|
| 553 |
}
|
| 554 |
|
| 555 |
return $commissions;
|
| 556 |
}
|
| 557 |
|
| 558 |
/**
|
| 559 |
* Save product's commissions data to DB.
|
| 560 |
*
|
| 561 |
* @param array $data
|
| 562 |
* Array in format of:
|
| 563 |
* $data[$nid][$affid] = array(
|
| 564 |
* 'commission' => $commission_array,
|
| 565 |
* 'allowed' => PRODUCT_DISABLED_FOR_AFFILIATES | PRODUCT_ENABLED_FOR_AFFILIATES | PRODUCT_DEFAULT_FOR_AFFILIATES,
|
| 566 |
* )
|
| 567 |
*/
|
| 568 |
function uc_affiliate_set_product_commissions_data($data) {
|
| 569 |
foreach ($data as $nid => $by_affid) {
|
| 570 |
db_query('DELETE FROM {uc_affiliate_products} WHERE nid = %d', $nid);
|
| 571 |
foreach ($by_affid as $affid => $comm) {
|
| 572 |
$comm['nid'] = $nid;
|
| 573 |
$comm['affid'] = $affid;
|
| 574 |
if (is_array($comm['commission'])) {
|
| 575 |
$comm['commission'] = serialize($comm['commission']);
|
| 576 |
}
|
| 577 |
drupal_write_record('uc_affiliate_products', $comm);
|
| 578 |
}
|
| 579 |
}
|
| 580 |
}
|
| 581 |
|
| 582 |
/**
|
| 583 |
* Converts commission array to string representation.
|
| 584 |
*/
|
| 585 |
function uc_affiliate_commission2str($commission, $format_currency = FALSE, &$rec = FALSE) {
|
| 586 |
$result = '';
|
| 587 |
$context = array(
|
| 588 |
'revision' => 'formatted-original',
|
| 589 |
'location' => 'affiliate-commission',
|
| 590 |
);
|
| 591 |
|
| 592 |
if (is_array($commission) && !empty($commission)) {
|
| 593 |
if (isset($commission['commission'])) {
|
| 594 |
$commission['commission'] = uc_affiliate_commission2str($commission['commission'], $format_currency, $rec);
|
| 595 |
return $commission;
|
| 596 |
}
|
| 597 |
|
| 598 |
$k = (string)key($commission);
|
| 599 |
if (($k == 'value') || ($k == 'type')) {
|
| 600 |
switch ($commission['type']) {
|
| 601 |
case 'currency':
|
| 602 |
if ($format_currency) {
|
| 603 |
$result = uc_price($commission['value'], $context);
|
| 604 |
}
|
| 605 |
else {
|
| 606 |
$result = $commission['value'];
|
| 607 |
}
|
| 608 |
break;
|
| 609 |
case 'percent':
|
| 610 |
$result = $commission['value'] .'%';
|
| 611 |
break;
|
| 612 |
}
|
| 613 |
$rec = TRUE;
|
| 614 |
}
|
| 615 |
else {
|
| 616 |
if (!empty($commission)) {
|
| 617 |
foreach ($commission as $level => $data) {
|
| 618 |
$arr[] = uc_affiliate_commission2str($data, $format_currency, $rec);
|
| 619 |
}
|
| 620 |
if ($rec) {
|
| 621 |
$result = implode('; ', $arr);
|
| 622 |
}
|
| 623 |
$rec = FALSE;
|
| 624 |
}
|
| 625 |
}
|
| 626 |
}
|
| 627 |
return $result;
|
| 628 |
}
|
| 629 |
|
| 630 |
/**
|
| 631 |
* Validate commission form element.
|
| 632 |
*/
|
| 633 |
function uc_affiliate_validate_commission($form_element, &$form_state) {
|
| 634 |
$result = uc_affiliate_parse_commission($form_element['#value']);
|
| 635 |
|
| 636 |
if (!is_array($result)) {
|
| 637 |
if ($result == ERROR_COMMISSION_NOT_NUMBER) {
|
| 638 |
form_set_error($form_element['#name'], t('Must be a positive number, percent or blank.'));
|
| 639 |
}
|
| 640 |
elseif ($result == ERROR_COMMISSION_CANT_BE_NEGATIVE) {
|
| 641 |
form_set_error($form_element['#name'], t('Commission can not be negative.'));
|
| 642 |
}
|
| 643 |
elseif ($result == ERROR_COMMISSION_NOT_NUMBER) {
|
| 644 |
form_set_error($form_element['#name'], t('Must be between 0% and 100%.'));
|
| 645 |
}
|
| 646 |
else {
|
| 647 |
form_set_error($form_element['#name'], t('Something wrong happened during validation.'));
|
| 648 |
}
|
| 649 |
}
|
| 650 |
}
|
| 651 |
|
| 652 |
/**
|
| 653 |
* Parse commission string and return array representation.
|
| 654 |
*/
|
| 655 |
function uc_affiliate_parse_commission($string, $return_serialized = FALSE) {
|
| 656 |
$commissions = array();
|
| 657 |
$string = trim($string);
|
| 658 |
|
| 659 |
if ($string != '') {
|
| 660 |
$chunks = explode(';', $string);
|
| 661 |
if (!empty($chunks)) {
|
| 662 |
foreach ($chunks as $value) {
|
| 663 |
$value = trim($value);
|
| 664 |
if (preg_match('@%$@', $value)) {
|
| 665 |
$value = preg_replace('@%$@', '', $value);
|
| 666 |
$type = 'percent';
|
| 667 |
}
|
| 668 |
else {
|
| 669 |
$type = 'currency';
|
| 670 |
}
|
| 671 |
if (!is_numeric($value)) {
|
| 672 |
return ERROR_COMMISSION_NOT_NUMBER;
|
| 673 |
}
|
| 674 |
else {
|
| 675 |
$value = (float)$value;
|
| 676 |
if ($value < 0) {
|
| 677 |
return ERROR_COMMISSION_CANT_BE_NEGATIVE;
|
| 678 |
}
|
| 679 |
if ($type == 'percent') {
|
| 680 |
if (($value < 0) || ($value > 100)) {
|
| 681 |
return ERROR_COMMISSION_PERCENT_OUT_OF_BORDERS;
|
| 682 |
}
|
| 683 |
}
|
| 684 |
}
|
| 685 |
$commissions[] = array('type' => $type, 'value' => $value);
|
| 686 |
}
|
| 687 |
}
|
| 688 |
}
|
| 689 |
|
| 690 |
if ($return_serialized) {
|
| 691 |
$commissions = serialize($commissions);
|
| 692 |
}
|
| 693 |
return $commissions;
|
| 694 |
}
|
| 695 |
|
| 696 |
/**
|
| 697 |
* Returns serialized array representing default commission value.
|
| 698 |
*/
|
| 699 |
function uc_affiliate_default_commission() {
|
| 700 |
return serialize(uc_affiliate_parse_commission('5%,3%,1%'));
|
| 701 |
}
|
| 702 |
|
| 703 |
/**
|
| 704 |
* Get user's time value.
|
| 705 |
*/
|
| 706 |
function _user_time() {
|
| 707 |
global $user;
|
| 708 |
if (variable_get('configurable_timezones', 1) && $user->uid && strlen($user->timezone)) {
|
| 709 |
return (time() - date("Z")) + $user->timezone;
|
| 710 |
}
|
| 711 |
else {
|
| 712 |
return (time() - date("Z")) + variable_get('date_default_timezone', 0);
|
| 713 |
}
|
| 714 |
}
|
| 715 |
|
| 716 |
/**
|
| 717 |
* Return the current time rounded down to the most recent chunk (day).
|
| 718 |
*/
|
| 719 |
function uc_affiliate_current_time() {
|
| 720 |
$time = time();
|
| 721 |
return $time - ($time % 86400);
|
| 722 |
}
|