query($sql); $data['productsPrices'] = []; while($row = $database->fetchArray($query)){ $productKey = $sumBy === 'type' ? $row['productType'] : $row['productCategory']; if(!isset($data['productsPrices'][$productKey])){ $data['productsPrices'][$productKey]['totalUnitCost'] = 0; $data['productsPrices'][$productKey]['totalVatCost'] = 0; } unset($totalCategoryUnitCost); unset($totalCategoryVatCost); $totalCategoryUnitCost =& $data['productsPrices'][$productKey]['totalUnitCost']; $totalCategoryVatCost =& $data['productsPrices'][$productKey]['totalVatCost']; if($sumBy === 'type' && $row['productType'] === 'service') { $totalUnitCost = $this->calculateTotalPrice(0, $row['unitCostPrice'], $row['payPeriod'], $row['quantity']); $totalVatCost = $this->calculateTotalPrice(0, $row['unitVatCost'], $row['payPeriod'], $row['quantity']); if($row['isPriceRecurring'] == 1) { if(!isset($data['productsPrices'][$row['productType']]['recurringPrice'])) { $data['productsPrices'][$row['productType']]['recurringPrice'] = 0; $data['productsPrices'][$row['productType']]['recurringVatPrice'] = 0; } $data['productsPrices'][$row['productType']]['recurringPrice'] += $totalUnitCost; $data['productsPrices'][$row['productType']]['recurringVatPrice'] += $totalVatCost; } else { if(!isset($data['productsPrices'][$row['productType']]['recurringPrice'])) { $data['productsPrices'][$row['productType']]['fixedPrice'] = 0; $data['productsPrices'][$row['productType']]['fixedVatPrice'] = 0; } $data['productsPrices'][$row['productType']]['fixedPrice'] += $totalUnitCost; $data['productsPrices'][$row['productType']]['fixedVatPrice'] += $totalVatCost; } } else { $totalUnitCost = $this->calculateTotalPrice($row['isPriceRecurring'], $row['unitCostPrice'], $row['payPeriod'], $row['quantity']); $totalVatCost = $this->calculateTotalPrice($row['isPriceRecurring'], $row['unitVatCost'], $row['payPeriod'], $row['quantity']); } if($row['productType'] === 'installation'){ $totalCategoryUnitCost = $this->getMultiProductsTotal($totalCategoryUnitCost, $totalUnitCost); $totalCategoryVatCost = $this->getMultiProductsTotal($totalCategoryVatCost, $totalVatCost); } else { $totalCategoryUnitCost += $totalUnitCost; $totalCategoryVatCost += $totalVatCost; } } return $data['productsPrices']; } /** * get commission split * @param INT $idPackage id for commission split * @return HashArray commission split percentqages */ public function getCommissionSplit($idPackage){ global $database; $sql = "SELECT bcs.brokerSplit as broker, bcs.commercialLeadSplit as commercialLead, bcs.payMargin FROM ".TABLES['broker_commission_split']." bcs WHERE idPackage=$idPackage"; $commissionSplit = $database->fetchResultArray($sql); return !empty($commissionSplit) ? $commissionSplit[0] : []; } /** * get product prices list and comissions * @param INT $idPackage id of the package * @param BOOLEAN $getOnlySelectedTpes if true will return just prices set by the broker * @return json list of prices and list of comission */ public function getPriceTypes($idPackage, $getOnlySelectedTpes = false){ global $database; $joinType = $getOnlySelectedTpes ? "INNER JOIN" : "LEFT OUTER JOIN"; $sql = "SELECT pt.id as idPaymentType, pt.payType, pt.packagePayPeriod, pt.servicesContractPeriod, pt.maxContractPeriod, pt.periodUnit, plb.minimalFixedPrice, plb.principalAmount, plb.minimalServicesPrice FROM ".TABLES['payment_types']." pt $joinType (SELECT idPaymentType, minimalFixedPrice, principalAmount, minimalServicesPrice FROM ".TABLES['price_list_broker']." WHERE idPackage=$idPackage) plb ON pt.id=plb.idPaymentType"; $query = $database->query($sql); while($row = $database->fetchArray($query)){ $row['minimalRecurentPrice'] = $row['packagePayPeriod'] > 0 ? $this->PMT($interestRateValue['interestRate'] / 100, $row['packagePayPeriod'], $row['principalAmount']) : 0; $row['minimalRecurentPrice'] = number_format($row['minimalRecurentPrice'], 2, '.', ''); $data['priceTypes'][] = $row; } } /** * get price list for commercial leads * @param INT $idPackage id for packge * @param INT $idCommercialLead id for commrcial lead or id for user , depends on $targetIdType * @param String $targetIdType target for the id, userId=> id for the user, roleId => id for the role * @return Array commercial lead price list */ public function getCommercialLeadPrices($idPackage = 0, $idCommercialLead = 0, $targetIdType = 'userId'){ global $database, $user; $idPackage = $database->escapeValue($idPackage); $whereSql = ""; $clPrices = []; if($idPackage){ $whereSql .= " AND plcl.idPackage=$idPackage"; } if($idCommercialLead){ $whereSql .= $targetIdType === 'userId' ? " AND cl.idUser=$idCommercialLead" : " AND cl.id=$idCommercialLead"; } $sql = "SELECT plcl.id AS idPrice, plcl.idPackage, plcl.idPaymentType, pt.payType, IFNULL(plcl.idCustomer, 0) as idCustomer, plcl.fixedExtra , plcl.recurentExtra, plcl.servicesExtra, plcl.visibleToCustomer, pt.packagePayPeriod FROM ".TABLES['price_list_commercial_lead']." plcl INNER JOIN ".TABLES['payment_types']." pt ON pt.id = plcl.idPaymentType INNER JOIN ".TABLES['commercial_leads']." cl ON cl.id=plcl.idCommercialLead WHERE 1=1 $whereSql"; $query = $database->query($sql); while($row = $database->fetchArray($query)){ $clPrices[$row['idPackage']][$row['idCustomer']][$row['idPaymentType']] = $row; } return $clPrices; } /** * calculate total cost for a package * @param HasArray $productsPrices product prices grouped by categoreis * @return Float total cost */ public function calculatePackageTotalCost($productsPrices){ $total = 0; foreach ($productsPrices as $category) { $total += $category['totalUnitCost']; } return $total; } /** * calculate package total margin * @param HashArray $payType pay type hash array (minimalFixedPrice and principalAmount keys required) * @param Float $totalCost total cost for package * @return Float package margin */ private function calculateMargin($payType, $totalCost){ $totalGain = $payType['minimalFixedPrice'] + $payType['principalAmount']; return $totalGain - $totalCost; } /** * get price margins based on comission split * @param HashArray $commisisonPercent commission split (commercialLead and broker keys requried) * @param HashArray $payType pay type hash array (required to get the margin) * @param Float $totalCost total cost for package * @return HashArray margins per user role */ public function getPriceMargins($commisisonPercent, $payType, $totalCost){ $margin = $this->calculateMargin($payType, $totalCost); if($margin < 0){ return [ 'margin' => 0, 'clMargin' => 0, 'brokerMargin' => 0 ]; }else{ return [ 'margin' => $margin, 'clMargin' => ($margin * $commisisonPercent['commercialLead'] / 100), 'brokerMargin' => ($margin * $commisisonPercent['broker'] / 100) ]; } } /** * Copy of Excel's PMT function. * Credit: http://thoughts-of-laszlo.blogspot.nl/2012/08/complete-formula-behind-excels-pmt.html * * @param double $interest The interest rate for the loan. * @param int $num_of_payments The total number of payments for the loan in months. * @param double $PV The present value, or the total amount that a series of future payments is worth now; * Also known as the principal. * @param double $FV The future value, or a cash balance you want to attain after the last payment is made. * If fv is omitted, it is assumed to be 0 (zero), that is, the future value of a loan is 0. * @param int $Type Optional, defaults to 0. The number 0 (zero) or 1 and indicates when payments are due. * 0 = At the end of period * 1 = At the beginning of the period * * @return float */ public function PMT($interest, $num_of_payments, $PV, $FV = 0.00, $Type = 0){ /*$interest = $interest / 12; $xp=pow((1+$interest),$num_of_payments); return ($PV* $interest*$xp/($xp-1)+$interest/($xp-1)*$FV)* ($Type==0 ? 1 : 1/($interest+1));*/ $rates = [ 24 => 4.282, 30 => 3.451, 36 => 2.896, 42 => 2.500, 48 => 2.223, 54 => 2.025, 60 => 1.834 ]; $interest = isset($rates[$num_of_payments]) ? $rates[$num_of_payments] : 10; return round($PV * ($interest / 100)); } /** * calculate fixed mortage based on principal amount * @param HashArray $payType pay type hash array (principalAmount and packagePayPeriod keys required) * @param Float $clMargin commercial lead margin * @param Float $interestRate interest rate percent value * @return Float fixed mortage formated to two decimals */ public function getRecurrentPriceMortage($payType, $clMargin, $interestRate){ $newPrincipalAmount = $payType['principalAmount'] - $clMargin; $interestRate = $interestRate / 100; $fixedMortage = $this->PMT($interestRate, $payType['packagePayPeriod'], $newPrincipalAmount); return number_format($fixedMortage, 2, '.', ''); } }