324 lines
14 KiB
PHP
324 lines
14 KiB
PHP
<?php
|
|
|
|
class Prices{
|
|
/**
|
|
* calculate total price for a product in a package
|
|
* @param boolean $isRecurring is the price recurring
|
|
* @param FLOAT $unitCost cost for the product
|
|
* @param INT $payPeriod pay period in case of recurring
|
|
* @param INT $quantity quantity of the product in the package
|
|
* @return FLOAT total cost for a prodcut
|
|
*/
|
|
private function calculateTotalPrice($isRecurring, $unitCost, $payPeriod, $quantity){
|
|
$totalUnitCost = intVal($isRecurring) === 1
|
|
? intVal($unitCost) * intVal($payPeriod)
|
|
: intVal($unitCost);
|
|
$totalUnitCost *= $quantity;
|
|
|
|
return $totalUnitCost;
|
|
}
|
|
|
|
/**
|
|
* get max price for products with multiple selection
|
|
* @param FLOAT $totalCategoryUnitCost max value for category
|
|
* @param FLOAT $totalUnitCost cost of the product
|
|
* @return FLOAT final cost for the product
|
|
*/
|
|
private function getMultiProductsTotal($totalCategoryUnitCost, $totalUnitCost){
|
|
return $totalCategoryUnitCost < $totalUnitCost
|
|
? $totalUnitCost
|
|
: $totalCategoryUnitCost;
|
|
}
|
|
|
|
/**
|
|
* get pacakge product prices grouped by categories
|
|
* @param INT $idPackage id for package
|
|
* @return Array product prices
|
|
*/
|
|
public function getPackageProductPrices($idPackage, $sumBy = 'category'){
|
|
global $database;
|
|
|
|
$sql = "SELECT scp.unitCostPrice AS unitCostPrice,
|
|
scp.unitVatCost AS unitVatCost,
|
|
scp.isPriceRecurring AS isPriceRecurring,
|
|
scp.payPeriod AS payPeriod,
|
|
pc.category AS productCategory,
|
|
pt.type AS productType,
|
|
rpp.quantity AS quantity
|
|
FROM ".TABLES['suppliers_countries_products']." scp
|
|
INNER JOIN ".TABLES['product_categories']." pc
|
|
ON pc.id=scp.idProductCategory
|
|
INNER JOIN ".TABLES['product_types']." pt
|
|
ON pt.id = pc.idType
|
|
INNER JOIN ".TABLES['rel_package_products']." rpp
|
|
ON rpp.idProduct=scp.idProduct
|
|
INNER JOIN
|
|
(SELECT
|
|
rpp_last.idPackage,
|
|
MAX(rpp_last.packageInstance) AS maxInstance
|
|
FROM
|
|
".TABLES['rel_package_products']." rpp_last
|
|
GROUP BY rpp_last.idPackage) last_instance
|
|
ON last_instance.idPackage = rpp.idPackage
|
|
AND last_instance.maxInstance = rpp.packageInstance
|
|
WHERE rpp.idPackage=$idPackage";
|
|
|
|
$query = $database->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, '.', '');
|
|
}
|
|
}
|