public function qualification(Request\Qualification $req)
 {
     $result = new Response\Qualification();
     $datePerformed = $req->getDatePerformed();
     $dateApplied = $req->getDateApplied();
     $gvMaxLevels = $req->getGvMaxLevels();
     $msg = "'Qualification for Global Sales' calculation is started. " . "Performed at: {$datePerformed}, applied at: {$dateApplied}.";
     $this->_logger->info($msg);
     $reqGetPeriod = new PeriodGetForDependentCalcRequest();
     $calcTypeBase = Cfg::CODE_TYPE_CALC_COMPRESSION;
     $calcType = Cfg::CODE_TYPE_CALC_QUALIFICATION;
     $reqGetPeriod->setBaseCalcTypeCode($calcTypeBase);
     $reqGetPeriod->setDependentCalcTypeCode($calcType);
     $respGetPeriod = $this->_callBasePeriod->getForDependentCalc($reqGetPeriod);
     if ($respGetPeriod->isSucceed()) {
         $def = $this->_manTrans->begin();
         try {
             $periodDataDepend = $respGetPeriod->getDependentPeriodData();
             $calcDataDepend = $respGetPeriod->getDependentCalcData();
             $calcIdDepend = $calcDataDepend->getId();
             $calcDataBase = $respGetPeriod->getBaseCalcData();
             $dsBegin = $periodDataDepend->getDstampBegin();
             $dsEnd = $periodDataDepend->getDstampEnd();
             $calcIdBase = $calcDataBase->getId();
             $tree = $this->_repoBonusCompress->getTreeByCalcId($calcIdBase);
             $qualData = $this->_repoMod->getQualificationData($dsBegin, $dsEnd);
             $cfgParams = $this->_repoMod->getConfigParams();
             $updates = $this->_subQualification->calcParams($tree, $qualData, $cfgParams, $gvMaxLevels);
             $this->_repoMod->saveQualificationParams($updates);
             $this->_repoBonusService->markCalcComplete($calcIdDepend);
             $this->_manTrans->commit($def);
             $result->setPeriodId($periodDataDepend->getId());
             $result->setCalcId($calcIdDepend);
             $result->markSucceed();
         } finally {
             $this->_manTrans->end($def);
         }
     }
     $this->_logger->info("'Qualification for Global Sales' calculation is complete.");
     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;
 }