/** * @param Request\GetForWriteOff $request * * @return Response\GetForWriteOff */ public function getForWriteOff(Request\GetForWriteOff $request) { $result = new Response\GetForWriteOff(); $this->_logger->info("'Get latest period for Write Off calculation' operation is started."); /* get the last Write Off period data */ $calcWriteOffCode = Cfg::CODE_TYPE_CALC_PV_WRITE_OFF; $calcWriteOffId = $this->_subDb->getCalcIdByCode($calcWriteOffCode); $respWriteOffLastPeriod = $this->_subDb->getLastPeriodData($calcWriteOffId); $periodWriteOffData = $respWriteOffLastPeriod->getPeriodData(); if (is_null($periodWriteOffData)) { $this->_logger->info("There is no period for PV Write Off calculation yet."); /* calc period for PV Write Off */ $tsFirstPv = $this->_subDb->getFirstDateForPvTransactions(); if ($tsFirstPv === false) { $this->_logger->info("There is no PV transactions yet. Nothing to do."); $result->setHasNoPvTransactionsYet(); } else { $this->_logger->info("First PV transaction was performed at '{$tsFirstPv}'."); $periodMonth = $this->_toolPeriod->getPeriodCurrent($tsFirstPv, ToolPeriod::TYPE_MONTH); $dsBegin = $this->_toolPeriod->getPeriodFirstDate($periodMonth); $dsEnd = $this->_toolPeriod->getPeriodLastDate($periodMonth); $periodWriteOffData = $this->_subDb->addNewPeriodAndCalc($calcWriteOffId, $dsBegin, $dsEnd); $result->setPeriodData($periodWriteOffData->getData(Sub\Db::DATA_PERIOD)); $result->setCalcData($periodWriteOffData->getData(Sub\Db::DATA_CALC)); $result->markSucceed(); } } else { $result->setPeriodData($periodWriteOffData); $periodId = $periodWriteOffData->getId(); $this->_logger->info("There is registered period #{$periodId} for '{$calcWriteOffCode}' calculation."); $calcData = $respWriteOffLastPeriod->getCalcData(); if ($calcData === false) { $this->_logger->info("There is no calculation data for existing period. Use existing period data."); $result->markSucceed(); } else { if ($calcData && $calcData->getState() == Cfg::CALC_STATE_COMPLETE) { $this->_logger->info("There is complete calculation for existing period. Create new period."); $periodEnd = $periodWriteOffData->getDstampEnd(); /* calculate new period bounds */ $periodNext = $this->_toolPeriod->getPeriodNext($periodEnd, ToolPeriod::TYPE_MONTH); $dsNextBegin = $this->_toolPeriod->getPeriodFirstDate($periodNext); $dsNextEnd = $this->_toolPeriod->getPeriodLastDate($periodNext); $periodWriteOffData = $this->_subDb->addNewPeriodAndCalc($calcWriteOffId, $dsNextBegin, $dsNextEnd); $result->setPeriodData($periodWriteOffData->getData(Sub\Db::DATA_PERIOD)); $result->setCalcData($periodWriteOffData->getData(Sub\Db::DATA_CALC)); $result->markSucceed(); } else { $this->_logger->info("There is no complete calculation for existing period. Use existing period data."); $result->setCalcData($calcData); $result->markSucceed(); } } } $this->_logger->info("'Get latest period for Write Off calculation' operation is completed."); return $result; }
public function calcBalances($currentBalances, $transactions) { $result = []; foreach ($transactions as $one) { $accDebit = $one[Transaction::ATTR_DEBIT_ACC_ID]; $accCredit = $one[Transaction::ATTR_CREDIT_ACC_ID]; $timestamp = $one[Transaction::ATTR_DATE_APPLIED]; $date = $this->_toolPeriod->getPeriodCurrent($timestamp, IPeriod::TYPE_DAY); $changeValue = $one[Transaction::ATTR_VALUE]; /** * process debit account */ /* get calculated balance on the date*/ if (isset($result[$accDebit][$date])) { /* there is data for this account on this date */ $data = $result[$accDebit][$date]; } else { /* there is NO data for this account on this date */ $data = [Balance::ATTR_ACCOUNT_ID => $accDebit, Balance::ATTR_DATE => $date, Balance::ATTR_BALANCE_OPEN => 0, Balance::ATTR_TOTAL_DEBIT => 0, Balance::ATTR_TOTAL_CREDIT => 0, Balance::ATTR_BALANCE_CLOSE => 0]; /* we need to update opening balance */ if (isset($result[$accDebit])) { $last = end($result[$accDebit]); $data[Balance::ATTR_BALANCE_OPEN] = $last[Balance::ATTR_BALANCE_CLOSE]; } elseif (isset($currentBalances[$accDebit])) { $data[Balance::ATTR_BALANCE_OPEN] = $currentBalances[$accDebit][Balance::ATTR_BALANCE_CLOSE]; } } /* change debit related values */ $data[Balance::ATTR_TOTAL_DEBIT] += $changeValue; $data[Balance::ATTR_BALANCE_CLOSE] -= $changeValue; $result[$accDebit][$date] = $data; /** * process credit account */ /* get calculated balance on the date*/ if (isset($result[$accCredit][$date])) { /* there is data for this account on this date */ $data = $result[$accCredit][$date]; } else { /* there is NO data for this account on this date */ $data = [Balance::ATTR_ACCOUNT_ID => $accCredit, Balance::ATTR_DATE => $date, Balance::ATTR_BALANCE_OPEN => 0, Balance::ATTR_TOTAL_DEBIT => 0, Balance::ATTR_TOTAL_CREDIT => 0, Balance::ATTR_BALANCE_CLOSE => 0]; /* we need to update opening balance */ if (isset($result[$accCredit])) { $last = end($result[$accCredit]); $data[Balance::ATTR_BALANCE_OPEN] = $last[Balance::ATTR_BALANCE_CLOSE]; } elseif (isset($currentBalances[$accCredit])) { $data[Balance::ATTR_BALANCE_OPEN] = $currentBalances[$accCredit][Balance::ATTR_BALANCE_CLOSE]; } } /* change credit related values */ $data[Balance::ATTR_TOTAL_CREDIT] += $changeValue; $data[Balance::ATTR_BALANCE_CLOSE] += $changeValue; $result[$accCredit][$date] = $data; } return $result; }
public function getLastDate(Request\GetLastDate $request) { $result = new Response\GetLastDate(); $assetTypeId = $request->getAssetTypeId(); $assetTypeCode = $request->getAssetTypeCode(); if (is_null($assetTypeId)) { $assetTypeId = $this->_repoTypeAsset->getIdByCode($assetTypeCode); } /* get the maximal date for balance */ $balanceMaxDate = $this->_repoMod->getBalanceMaxDate($assetTypeId); if ($balanceMaxDate) { /* there is balance data */ $dayBefore = $this->_toolPeriod->getPeriodPrev($balanceMaxDate, IPeriod::TYPE_DAY); $result->setData([Response\GetLastDate::LAST_DATE => $dayBefore]); $result->markSucceed(); } else { /* there is no balance data yet, get transaction with minimal date */ $transactionMinDate = $this->_repoMod->getTransactionMinDateApplied($assetTypeId); if ($transactionMinDate) { $period = $this->_toolPeriod->getPeriodCurrent($transactionMinDate); $dayBefore = $this->_toolPeriod->getPeriodPrev($period, IPeriod::TYPE_DAY); $result->setData([Response\GetLastDate::LAST_DATE => $dayBefore]); $result->markSucceed(); } } return $result; }
/** * * Get PV related period data if no period yet exist. * * @param \Praxigento\BonusBase\Service\Period\Response\GetForPvBasedCalc $result * @param string $periodType * @param int $calcTypeId * @return \Praxigento\BonusBase\Service\Period\Response\GetForPvBasedCalc */ public function getNewPeriodDataForPv(\Praxigento\BonusBase\Service\Period\Response\GetForPvBasedCalc $result, $periodType, $calcTypeId) { /* we should lookup for first PV transaction and calculate first period range */ $firstDate = $this->_repoService->getFirstDateForPvTransactions(); if ($firstDate === false) { $this->_logger->warning("There is no PV transactions yet. Nothing to do."); $result->setErrorCode($result::ERR_HAS_NO_PV_TRANSACTIONS_YET); } else { $this->_logger->info("First PV transaction was performed at '{$firstDate}'."); $periodMonth = $this->_toolPeriod->getPeriodCurrent($firstDate, $periodType); $dsBegin = $this->_toolPeriod->getPeriodFirstDate($periodMonth); $dsEnd = $this->_toolPeriod->getPeriodLastDate($periodMonth); /* create new period for given calculation type */ $period = new EPeriod(); $period->setCalcTypeId($calcTypeId); $period->setDstampBegin($dsBegin); $period->setDstampEnd($dsEnd); $periodId = $this->_repoPeriod->create($period); $period->setId($periodId); /* create related calculation */ $calc = new ECalculation(); $calc->setPeriodId($periodId); $dateStarted = $this->_toolDate->getUtcNowForDb(); $calc->setDateStarted($dateStarted); $calc->setState(Cfg::CALC_STATE_STARTED); $calcId = $this->_repoCalc->create($calc); $calc->setId($calcId); /* place newly created objects into the response */ $result->setPeriodData($period); $result->setCalcData($calc); } return $result; }
/** * Calculate the last date for existing downline snap or the "yesterday" for the first change log entry. * * @param Request\GetLastDate $request * * @return Response\GetLastDate */ public function getLastDate(Request\GetLastDate $request) { $result = new Response\GetLastDate(); $this->_logger->info("'Get Last Data' operation is requested."); /* get the maximal date for existing snapshot */ $snapMaxDate = $this->_repoSnap->getMaxDatestamp(); if ($snapMaxDate) { /* there is snapshots data */ $result->setData([Response\GetLastDate::LAST_DATE => $snapMaxDate]); $result->markSucceed(); } else { /* there is no snapshot data yet, get change log minimal date */ $changelogMinDate = $this->_repoChange->getChangelogMinDate(); if ($changelogMinDate) { $period = $this->_toolPeriod->getPeriodCurrent($changelogMinDate); $dayBefore = $this->_toolPeriod->getPeriodPrev($period); $this->_logger->info("The last date for downline snapshot is '{$dayBefore}'."); $result->setData([Response\GetLastDate::LAST_DATE => $dayBefore]); $result->markSucceed(); } } $this->_logger->info("'Get Last Data' operation is completed."); return $result; }
/** * Calculate downline snapshots by date basing on the last snapshot and change log. * * We use $currentState array to trace actual state during the changes. Target updates are placed in the $result. * * @param $currentState * @param $changes * * @return array */ public function calcSnapshots($currentState, $changes) { $result = []; foreach ($changes as $downCustomer) { $customerId = $downCustomer[Change::ATTR_CUSTOMER_ID]; $parentId = $downCustomer[Change::ATTR_PARENT_ID]; $tsChanged = $downCustomer[Change::ATTR_DATE_CHANGED]; $dsChanged = $this->_toolPeriod->getPeriodCurrent($tsChanged); /* $currentState contains actual state that is updated with changes */ if (isset($currentState[$customerId])) { /* this is update of the existing customer */ /* write down existing state */ $currCustomer = $currentState[$customerId]; $currDepth = $currCustomer[Snap::ATTR_DEPTH]; $currPath = $currCustomer[Snap::ATTR_PATH]; /* write down new state */ if ($customerId == $parentId) { /* this is root node customer */ $newDepth = Cfg::INIT_DEPTH; $newPath = Cfg::DTPS; } else { /* this is NOT root node customer */ $newParent = $currentState[$parentId]; $newDepth = $newParent[Snap::ATTR_DEPTH] + 1; $newPath = $newParent[Snap::ATTR_PATH] . $parentId . Cfg::DTPS; } $customer = [Snap::ATTR_DATE => $dsChanged, Snap::ATTR_CUSTOMER_ID => $customerId, Snap::ATTR_PARENT_ID => $parentId, Snap::ATTR_DEPTH => $newDepth, Snap::ATTR_PATH => $newPath]; /* we need to update downline's depths & paths for changed customer */ /* TODO slow code, add ndx if too much slow */ $key = $currPath . $customerId . Cfg::DTPS; $depthDelta = $newDepth - $currDepth; $pathReplace = $newPath . $customerId . Cfg::DTPS; foreach ($currentState as $downCustomer) { $downPath = $downCustomer[Snap::ATTR_PATH]; if (false !== strrpos($downPath, $key, -strlen($downPath))) { /* this is customer from downlilne, we need to change depth & path */ $downCustId = $downCustomer[Snap::ATTR_CUSTOMER_ID]; $downParentId = $downCustomer[Snap::ATTR_PARENT_ID]; $downNewDepth = $downCustomer[Snap::ATTR_DEPTH] + $depthDelta; $downNewPath = str_replace($key, $pathReplace, $downCustomer[Snap::ATTR_PATH]); $downCustomer[Snap::ATTR_DEPTH] = $downNewDepth; $downCustomer[Snap::ATTR_PATH] = $downNewPath; /* add to result updates */ $result[$dsChanged][$downCustId] = [Snap::ATTR_DATE => $dsChanged, Snap::ATTR_CUSTOMER_ID => $downCustId, Snap::ATTR_PARENT_ID => $downParentId, Snap::ATTR_DEPTH => $downNewDepth, Snap::ATTR_PATH => $downNewPath]; } } } else { /* there is no data for this customer, this is new customer; just add new customer to results */ if ($customerId == $parentId) { /* this is root node customer */ $customer = [Snap::ATTR_DATE => $dsChanged, Snap::ATTR_CUSTOMER_ID => $customerId, Snap::ATTR_PARENT_ID => $customerId, Snap::ATTR_DEPTH => Cfg::INIT_DEPTH, Snap::ATTR_PATH => Cfg::DTPS]; } else { /* this is NOT root node customer */ $parent = $currentState[$parentId]; $customer = [Snap::ATTR_DATE => $dsChanged, Snap::ATTR_CUSTOMER_ID => $customerId, Snap::ATTR_PARENT_ID => $parentId, Snap::ATTR_DEPTH => $parent[Snap::ATTR_DEPTH] + 1, Snap::ATTR_PATH => $parent[Snap::ATTR_PATH] . $parentId . Cfg::DTPS]; } } $currentState[$customerId] = $customer; $result[$dsChanged][$customerId] = $customer; } return $result; }