/** * @param array $tree * @param array $orders * @param array $params configuration parameters ordered desc (from up to down) * @param array $percents * * @return array */ public function calc($tree, $orders, $params, $percents) { $result = []; $mapTreeExp = $this->_expandTree($tree); $mapRankById = $this->_rankQualifier->qualifyCustomers($tree, $params); foreach ($orders as $order) { $custId = $order[Cfg::E_SALE_ORDER_A_CUSTOMER_ID]; $orderId = $order[PvSale::ATTR_SALE_ID]; $pv = $order[PvSale::ATTR_TOTAL]; $path = $mapTreeExp[$custId][Snap::ATTR_PATH]; $parents = $this->_toolDownlineTree->getParentsFromPathReversed($path); $gen = 1; foreach ($parents as $parentId) { if (isset($mapRankById[$parentId])) { $parentRank = $mapRankById[$parentId]; if (isset($percents[$parentRank][$gen])) { $percent = $percents[$parentRank][$gen]; $bonus = $pv * $percent; $bonus = $this->_toolFormat->roundBonus($bonus); $result[$parentId][$orderId] = $bonus; } } $gen++; } } return $result; }
public function calcParams($tree, $qData, $gvMaxLevels, $psaaLevel) { $treeExpanded = $this->_expandTree($tree); $mapByDepth = $this->_mapByTreeDepthDesc($treeExpanded); $mapTeams = $this->_mapByTeams($tree); $mapById = $this->_mapById($tree); $result = []; foreach ($mapByDepth as $depth => $level) { foreach ($level as $custId) { /* init result entry for the customer if entry is not exist */ if (!isset($result[$custId])) { $result[$custId] = $this->_initEntry(); $result[$custId][EntityQual::ATTR_COMPRESS_ID] = $mapById[$custId][Compress::ATTR_ID]; } /* process PV */ $pv = $qData[$custId]; $result[$custId][EntityQual::ATTR_PV] = $pv; /* process GV */ $path = $treeExpanded[$custId][Snap::ATTR_PATH]; $parents = $this->_toolDownlineTree->getParentsFromPathReversed($path); $gen = 1; foreach ($parents as $parentId) { if ($gen > $gvMaxLevels) { break; } if (!isset($result[$parentId])) { $result[$parentId] = $this->_initEntry(); $result[$parentId][EntityQual::ATTR_COMPRESS_ID] = $mapById[$parentId][Compress::ATTR_ID]; } $result[$parentId][EntityQual::ATTR_GV] += $pv; $gen++; } /* process PSAA */ if (isset($mapTeams[$custId])) { $psaa = 0; $team = $mapTeams[$custId]; foreach ($team as $memberId) { $mPv = $result[$memberId][EntityQual::ATTR_PV]; if ($mPv > $psaaLevel) { $psaa++; } } $result[$custId][EntityQual::ATTR_PSAA] = $psaa; } } } return $result; }
/** * @param Request\QualifyByUserData $req * * @return Response\QualifyByUserData */ public function qualifyByUserData(Request\QualifyByUserData $req) { $result = new Response\QualifyByUserData(); /* parse request */ $calcId = $req->getCalcId(); $treeFlat = $req->getFlatTree(); $qualifier = $req->getQualifier(); $skipExpand = (bool) $req->getSkipTreeExpand(); $this->_logger->info("'QualifyByUserData' operation is started."); $treeCompressed = []; if ($skipExpand) { $treeExpanded = $treeFlat; } else { $treeExpanded = $this->_toolDownlineTree->expandMinimal($treeFlat, ESnap::ATTR_PARENT_ID); } $mapById = $this->_mapById($treeExpanded); $mapDepth = $this->_mapByTreeDepthDesc($treeExpanded); $mapTeams = $this->_mapByTeams($treeExpanded); foreach ($mapDepth as $depth => $levelCustomers) { foreach ($levelCustomers as $custId) { $custData = $mapById[$custId]; $ref = isset($custData[Customer::ATTR_HUMAN_REF]) ? $custData[Customer::ATTR_HUMAN_REF] : ''; if ($qualifier->isQualified($custData)) { $this->_logger->info("Customer #{$custId} ({$ref}) is qualified and added to compressed tree."); $treeCompressed[$custId] = $custData; } else { $this->_logger->info("Customer #{$custId} ({$ref}) is not qualified."); if (isset($mapTeams[$custId])) { $this->_logger->info("Customer #{$custId} ({$ref}) has own front team."); /* Lookup for the closest qualified parent */ $path = $treeExpanded[$custId][ESnap::ATTR_PATH]; $parents = $this->_toolDownlineTree->getParentsFromPathReversed($path); $foundParentId = null; foreach ($parents as $newParentId) { $parentData = $mapById[$newParentId]; if ($qualifier->isQualified($parentData)) { $foundParentId = $newParentId; break; } } /* Change parent for all siblings of the unqualified customer. */ $team = $mapTeams[$custId]; foreach ($team as $memberId) { if (isset($treeCompressed[$memberId])) { /* if null set customer own id to indicate root node */ $treeCompressed[$memberId][ESnap::ATTR_PARENT_ID] = is_null($foundParentId) ? $memberId : $foundParentId; } } } } } } unset($mapCustomer); unset($mapPv); unset($mapDepth); unset($mapTeams); /* save compressed tree */ $def = $this->_manTrans->begin(); try { foreach ($treeCompressed as $custId => $item) { $data = [ECompress::ATTR_CALC_ID => $calcId, ECompress::ATTR_CUSTOMER_ID => $custId, ECompress::ATTR_PARENT_ID => $item[ESnap::ATTR_PARENT_ID]]; $this->_repoBonusCompress->create($data); } $this->_manTrans->commit($def); } finally { $this->_manTrans->end($def); } $result->markSucceed(); $this->_logger->info("'QualifyByUserData' operation is completed."); return $result; }
/** * Process Downline Tree snapshot, customer data and PV related transactions and compose data for compressed tree. * * @param $treeSnap array downline tree snapshot: [ $custId => [$customer_id, $parent_id, $depth, $path], ...]. * @param $customers array [ [$custId, $humanRef, $countryCode], ...] * @param $trans array of the PV related transactions. * * @return array data to save into prxgt_bon_hyb_compress */ public function compressPtc($treeSnap, $customers, $trans) { $qLevels = $this->_toolScheme->getQualificationLevels(); $forcedIds = $this->_toolScheme->getForcedQualificationCustomersIds(); $this->_logger->info("PTC Compression parameters:" . " qualification levels=" . var_export($qLevels, true) . ", forced customers: " . var_export($forcedIds, true)); /* array with results: [$customerId => [$pvCompressed, $parentCompressed], ... ]*/ $compressedTree = []; $mapCustomer = $this->_mapById($customers, Customer::ATTR_CUSTOMER_ID); $mapPv = $this->_mapByPv($trans, Account::ATTR_CUST_ID, Transaction::ATTR_VALUE); $mapDepth = $this->_mapByTreeDepthDesc($treeSnap, Snap::ATTR_CUSTOMER_ID, Snap::ATTR_DEPTH); $mapTeams = $this->_mapByTeams($treeSnap, Snap::ATTR_CUSTOMER_ID, Snap::ATTR_PARENT_ID); foreach ($mapDepth as $depth => $levelCustomers) { foreach ($levelCustomers as $custId) { $pv = isset($mapPv[$custId]) ? $mapPv[$custId] : 0; $parentId = $treeSnap[$custId][Snap::ATTR_PARENT_ID]; $custData = $mapCustomer[$custId]; $scheme = $this->_toolScheme->getSchemeByCustomer($custData); $level = $qLevels[$scheme]; // qualification level for current customer if ($pv >= $level || in_array($custId, $forcedIds)) { if (isset($compressedTree[$custId])) { $pvExist = $compressedTree[$custId][0]; $pvNew = $pv + $pvExist; $compressedTree[$custId] = [$pvNew, $parentId]; } else { $compressedTree[$custId] = [$pv, $parentId]; } } else { /* move PV up to the closest qualified parent (current customer's level is used for qualification) */ $path = $treeSnap[$custId][Snap::ATTR_PATH]; $parents = $this->_toolDownlineTree->getParentsFromPathReversed($path); $foundParentId = null; foreach ($parents as $newParentId) { $pvParent = isset($mapPv[$newParentId]) ? $mapPv[$newParentId] : 0; if ($pvParent >= $level || in_array($newParentId, $forcedIds)) { $foundParentId = $newParentId; break; } } unset($parents); /* add PV to this parent */ if (!is_null($foundParentId) && $pv > 0) { if (isset($compressedTree[$foundParentId])) { $pvExist = $compressedTree[$foundParentId][0]; $pvNew = $pv + $pvExist; $compressedTree[$foundParentId][0] = $pvNew; } else { $compressedTree[$foundParentId][0] = $pv; } $this->_logger->debug("{$pv} PV are transferred from customer #{$custId} to his qualified parent #{$foundParentId} ."); } /* change parent for all siblings of the unqualified customer */ if (isset($mapTeams[$custId])) { $team = $mapTeams[$custId]; foreach ($team as $memberId) { if (isset($compressedTree[$memberId])) { /* if null set customer own id to indicate root node */ $compressedTree[$memberId][1] = is_null($foundParentId) ? $memberId : $foundParentId; } } } } } } unset($mapCustomer); unset($mapPv); unset($mapDepth); unset($mapTeams); /* compose compressed snapshot data */ $data = $this->_composeSnapUpdates($compressedTree); /* add compressed PV data */ $result = $this->_populateCompressedSnapWithPv($data, $compressedTree); return $result; }
public function calcParams($tree, $qData, $cfgParams, $gvMaxLevels) { $treeExpanded = $this->_expandTree($tree); $mapByDepth = $this->_mapByTreeDepthDesc($treeExpanded); $mapById = $this->_mapById($tree); /* GV tree contains GV by legs for every customer: [$custId=>[$legCustId=>$gv, ...], ...] */ $gvTree = []; foreach ($mapByDepth as $depth => $level) { foreach ($level as $custId) { /* init node if not exist */ if (!isset($gvTree[$custId])) { $gvTree[$custId] = []; } $pv = $qData[$custId]; $path = $treeExpanded[$custId][Snap::ATTR_PATH]; $parents = $this->_toolDownlineTree->getParentsFromPathReversed($path); $lvl = 1; $legId = $custId; foreach ($parents as $parentId) { /* break on max level for GV calculation is exceeded */ if ($lvl > $gvMaxLevels) { break; } /* init node if not exist */ if (!isset($gvTree[$parentId])) { $gvTree[$parentId] = []; } /* add current PV to the parent on the current leg */ if (isset($gvTree[$parentId][$legId])) { $gvTree[$parentId][$legId] += $pv; } else { $gvTree[$parentId][$legId] = $pv; } /* increase levels counter and switch current leg id */ $lvl++; $legId = $parentId; } } } /* process intermediary GV values and calculate final results */ $result = []; foreach ($gvTree as $custId => $legs) { /* skip nodes without legs */ if (count($legs) == 0) { continue; } /* qualify max rank; for all ranks from min to max */ $rankIdQualified = null; $gvQualified = 0; foreach ($cfgParams as $rankId => $params) { $maxPercent = $params[Param::ATTR_LEG_MAX_PERCENT]; $gvRequired = $params[Param::ATTR_GV]; $gvMax = $gvRequired * $maxPercent; $gvTotal = 0; foreach ($legs as $gvLeg) { $gvTotal += $gvLeg > $gvMax ? $gvMax : $gvLeg; } /* total GV should not be less then required */ if ($gvTotal >= $gvRequired) { $rankIdQualified = $rankId; $gvQualified = $gvTotal; } else { break; } } /* add values to results */ if (!is_null($rankIdQualified)) { $compressId = $mapById[$custId][Compress::ATTR_ID]; $result[$custId] = [EntityQual::ATTR_COMPRESS_ID => $compressId, EntityQual::ATTR_RANK_ID => $rankIdQualified, EntityQual::ATTR_GV => $gvQualified]; } } return $result; }