/**
  * @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 bonusTeamEu($compressPtc, $teamBonusPercent)
 {
     $result = [];
     $mapDataById = $this->_mapById($compressPtc, PtcCompress::ATTR_CUSTOMER_ID);
     foreach ($mapDataById as $custId => $custData) {
         $custData = $mapDataById[$custId];
         $custRef = $custData[Customer::ATTR_HUMAN_REF];
         $scheme = $this->_toolScheme->getSchemeByCustomer($custData);
         if ($scheme == Def::SCHEMA_EU) {
             $pv = $custData[PtcCompress::ATTR_PV];
             if ($pv > Cfg::DEF_ZERO) {
                 $parentId = $custData[PtcCompress::ATTR_PARENT_ID];
                 $parentData = $mapDataById[$parentId];
                 $parentRef = $parentData[Customer::ATTR_HUMAN_REF];
                 $bonus = $this->_toolFormat->roundBonus($pv * $teamBonusPercent);
                 $result[] = [self::A_CUST_ID => $parentId, self::A_VALUE => $bonus, self::A_OTHER_ID => $custId];
                 $this->_logger->debug("Customer #{$parentId} (ref. #{$parentRef} ) has '{$bonus}' as EU Team Bonus from downline customer #{$custId} (ref. #{$custRef} ).");
             } else {
                 $this->_logger->debug("Customer #{$custId} (ref. #{$custRef} ) has no PV ({$pv} PV) and could not participate in EU Team Bonus.");
             }
         } else {
             $this->_logger->debug("Customer #{$custId} (ref. #{$custRef} ) has incompatible scheme '{$scheme}' for EU Team Bonus.");
         }
     }
     unset($mapDataById);
     return $result;
 }
 /**
  */
 public function calc($tree, $pvTotal, $params)
 {
     $mapMaxGvPerRank = $this->_mapRankMaxGv($params);
     $mapAmounts = $this->_mapPayoutsByRank($pvTotal, $params);
     /** @var array $mapRanks [$rankId=>[members=>[$custId=>GV, ...], totalGv=>$gv], ...] */
     $mapRanks = [];
     foreach ($tree as $customer) {
         $custId = $customer[Compress::ATTR_CUSTOMER_ID];
         $gvQual = $customer[Qualification::ATTR_GV];
         $rankQual = $customer[Qualification::ATTR_RANK_ID];
         foreach ($params as $rankId => $param) {
             $gvMax = $mapMaxGvPerRank[$rankId];
             $gv = $gvQual > $gvMax ? $gvMax : $gvQual;
             $mapRanks[$rankId][self::AS_MEMBERS][$custId] = $gv;
             if (!isset($mapRanks[$rankId][self::AS_TOTAL_GV])) {
                 $mapRanks[$rankId][self::AS_TOTAL_GV] = 0;
             }
             $mapRanks[$rankId][self::AS_TOTAL_GV] += $gv;
             /* break the loop if this is the MAX qualified rank */
             if ($rankId == $rankQual) {
                 break;
             }
         }
     }
     $result = [];
     foreach ($mapRanks as $rankId => $data) {
         $gvTotal = $data[self::AS_TOTAL_GV];
         $members = $data[self::AS_MEMBERS];
         $membersCount = count($members);
         $amountTotal = $mapAmounts[$rankId][self::AS_AMOUNT_TOTAL];
         $isProrated = $mapAmounts[$rankId][self::AS_IS_PRORATED];
         if ($isProrated) {
             /* share pro-rated */
             foreach ($members as $custId => $gv) {
                 $bonusProRated = $this->_toolFormat->roundBonus($amountTotal / $gvTotal * $gv);
                 $result[$custId][$rankId] = $bonusProRated;
             }
         } else {
             /* share equally */
             $bonusEqual = $this->_toolFormat->roundBonus($amountTotal / $membersCount);
             foreach ($members as $custId => $gv) {
                 $result[$custId][$rankId] = $bonusEqual;
             }
         }
     }
     return $result;
 }