Initial commit

This commit is contained in:
Senad Uka
2018-06-11 11:09:35 +02:00
commit ed7df7b11f
1954 changed files with 483354 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
<?php
class Bids {
public function getCartBids(){
global $database, $user;
$bids = [];
$pricesHandler = new Prices();
$interestRate = new InterestRate();
$interestRateValue = $interestRate->getInterestRate()['interestRate'];
$interestRateCustomers = $interestRate->getInterestRateForCustomers();
$sql = "SELECT
pb.id AS idBid,
pb.bidNumber,
pb.idPackage,
p.name AS packageName,
pb.idCustomerInstance,
pb.fixedExtra,
pb.recurrentExtra,
pb.servicesExtra,
c.id AS idCustomer,
c.name AS customer,
cl.name AS commercialLead,
pb.idPaymentType,
pt.payType,
pt.packagePayPeriod,
pt.periodUnit,
DATE_FORMAT(pb.startDate, '%D %b, %Y') AS startDate,
DATE_FORMAT(pb.endDate, '%D %b, %Y') AS endDate,
pb.fixedPrice,
pb.principalAmount,
pb.servicesPrice
FROM ".TABLES['packages_bids']." pb
INNER JOIN (
SELECT wsc.idPackage, wsc.idCustomerInstance, plcl.idPaymentType
FROM ".TABLES['web_shop_cart']." wsc
INNER JOIN ".TABLES['price_list_commercial_lead']." plcl
ON plcl.id=wsc.idPrice
WHERE wsc.idUser=".$user->getUserId()."
) wsc
ON wsc.idPackage=pb.idPackage AND wsc.idCustomerInstance=pb.idCustomerInstance AND wsc.idPaymentType=pb.idPaymentType
INNER JOIN ".TABLES['packages']." p
ON p.id=pb.idPackage
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id=pb.idCustomerInstance
INNER JOIN ".TABLES['customers']." c
ON c.id=rclc.idCustomer
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.id=rclc.idCommercialLead
INNER JOIN ".TABLES['payment_types']." pt
ON pt.id=pb.idPaymentType
WHERE pb.endDate > NOW()
ORDER BY pb.bidNumber";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$interestRateCust = $row['idCustomer'] && isset($interestRateCustomers[$row['idCustomer']]) ?
floatval($interestRateCustomers[$row['idCustomer']]) :
$interestRateValue;
$row['recurrentPrice'] = $row['packagePayPeriod'] > 0
? $pricesHandler->PMT($interestRateCust / 100, $row['packagePayPeriod'], $row['principalAmount'])
: 0;
$row['fixedPrice'] = floatval($row['fixedPrice']) + floatval($row['fixedExtra']);
$row['recurrentPrice'] = floatval($row['recurrentPrice']) + floatval($row['recurrentExtra']);
$row['servicesPrice'] = floatval($row['servicesPrice']) + floatval($row['servicesExtra']);
unset($row['fixedExtra']);
unset($row['recurrentExtra']);
unset($row['servicesExtra']);
$bids[$row['idPackage']][] = $row;
}
return $bids;
}
public function setBidForCart($idBid, $idCart){
global $database;
$data = [];
if(!$idBid){
$idBid = 'NULL';
}
if(!$idCart){
$data['messages'][] =[
'code' => 'error',
'message' => 'CART_REQUIRED'
];
return $data;
}
$idBid = $database->escapeValue($idBid);
$idCart = $database->escapeValue($idCart);
$sql = "UPDATE ".TABLES['web_shop_cart']."
SET idBid=$idBid
WHERE id=$idCart";
$query = $database->query($sql);
if($database->affectedRows() !== 1){
$data['messages'][] =[
'code' => 'error',
'message' => 'BID_NOT_USED'
];
}else{
$data['messages'][] = [
'code' => 'success',
'message' => 'BID_SET'
];
}
return $data;
}
}

View File

@@ -0,0 +1,103 @@
<?php
class SupplierBids{
public function getSuppliers(){
global $database;
$sql = "SELECT
s.id AS idSupplier,
s.name AS supplier
FROM ".TABLES['suppliers']." s
ORDER BY s.name";
return $database->fetchResultArray($sql);
}
public function getProducts($idSupplier){
global $database;
$sql = "SELECT
p.idProduct,
p.productName
FROM ".TABLES['suppliers_countries_products']." p
WHERE p.idSupplier=$idSupplier
ORDER BY p.productName";
return $database->fetchResultArray($sql);
}
public function addSupplierBid($supplierBid){
global $database;
$supplierBid = json_decode($supplierBid);
$sql = "INSERT INTO ".TABLES['supplier_bids']."
(idProduct, bidNumber)
VALUES(".$supplierBid->idProduct.", '".$supplierBid->bidNumber."')";
$query = $database->query($sql);
if($database->affectedRows() !== 1){
$data['messages'][] =[
'code' => 'error',
'message' => 'SERVER_ERROR'
];
return $data;
}
$data['messages'][] = [
'code' => 'success',
'message' => 'SUPPLIER_BID_ADDED'
];
return $data;
}
public function getUnlinkedSupplierBids(){
global $database;
$sql = "SELECT
sb.id AS idSupplierBid,
sb.bidNumber,
sb.idProduct,
p.productName,
s.name AS supplier
FROM ".TABLES['supplier_bids']." sb
INNER JOIN ".TABLES['suppliers_countries_products']." p
ON p.idProduct=sb.idProduct
INNER JOIN ".TABLES['suppliers']." s
ON s.id=p.idSupplier
LEFT OUTER JOIN ".TABLES['rel_bid_supplier_bids']." rbsb
ON rbsb.idSupplierBid=sb.id
WHERE rbsb.idSupplierBid IS NULL";
return $database->fetchResultArray($sql);
}
public function getLinkedSupplierBids(){
global $database;
$data = [];
$sql = "SELECT
sb.id AS idSupplierBid,
sb.bidNumber,
sb.idProduct,
p.productName,
s.name AS supplier,
rbsb.idBid
FROM ".TABLES['supplier_bids']." sb
INNER JOIN ".TABLES['suppliers_countries_products']." p
ON p.idProduct=sb.idProduct
INNER JOIN ".TABLES['suppliers']." s
ON s.id=p.idSupplier
INNER JOIN ".TABLES['rel_bid_supplier_bids']." rbsb
ON rbsb.idSupplierBid=sb.id";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idBid']][] = $row;
}
return $data;
}
}

View File

@@ -0,0 +1,112 @@
<?php
/**
* Cart controlls the actions for the shop
*/
class CartController{
private $model;
function __construct(){
$this->model = new CartModel();
}
/**
* get count of items in the cart
* @return json number of items in the cart
*/
public function getCartCount() {
echo json_encode($this->model->getCartCount(), JSON_NUMERIC_CHECK);
}
/**
* get items in cart
* @return json with array list of items in the cart
*/
public function getCartItems() {
echo json_encode($this->model->getCartItems(), JSON_NUMERIC_CHECK);
}
/**
* update the quantity in the cart for an item
* @return json update message
*/
public function updateQuantity() {
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idPrice = isset($_REQUEST['idPrice']) ? $_REQUEST['idPrice'] : 0;
$idCustomerInstance = isset($_REQUEST['idCustomerInstance']) ? $_REQUEST['idCustomerInstance'] : 0;
$quantity = isset($_REQUEST['quantity']) ? $_REQUEST['quantity'] : 1;
echo json_encode($this->model->updateQuantity($idPackage, $idCustomerInstance, $idPrice, $quantity));
}
/**
* remove items from carts
* @return json update message
*/
public function removeFromCart(){
$idCart = isset($_REQUEST['idCart']) ? $_REQUEST['idCart'] : 0;
echo json_encode($this->model->removeFromCart($idCart));
}
/**
* upload a questionaire form the cart page
* @return json upload message
*/
public function uploadOrderDocument(){
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
$idDocumentType = isset($_REQUEST['idDocumentType']) ? $_REQUEST['idDocumentType'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->uploadOrderDocument($file, $idDocumentType, $idPackage));
}
/**
* get document sfor packages in cart
* @return json Array of documents
*/
public function getCartDocuments(){
$packages = isset($_REQUEST['packages']) ? $_REQUEST['packages'] : [];
echo json_encode($this->model->getCartDocuments($packages), JSON_NUMERIC_CHECK);
}
public function setBidForCart(){
$idBid = isset($_REQUEST['idBid']) ? $_REQUEST['idBid'] : 0;
$idCart = isset($_REQUEST['idCart']) ? $_REQUEST['idCart'] : 0;
echo json_encode($this->model->setBidForCart($idBid, $idCart), JSON_NUMERIC_CHECK);
}
/**
* get details of the customer logged in
* @return json array with neccessary details
*/
public function getCustomerDetails() {
echo json_encode($this->model->getCustomerDetails(), JSON_NUMERIC_CHECK);
}
/**
* get all the countries
* @return json array with all countries
*/
public function getCountries() {
echo json_encode($this->model->getCountries());
}
/**
* save order delivery and billing addresses
* @return json Array messages
*/
public function saveOrderDetails(){
$orderDetails = isset($_REQUEST['orderDetails']) ? $_REQUEST['orderDetails'] : [];
$cartItems = isset($_REQUEST['cartItems']) ? $_REQUEST['cartItems'] : [];
echo json_encode($this->model->saveOrderDetails($orderDetails, $cartItems), JSON_NUMERIC_CHECK);
}
/**
* get document sfor packages in cart
* @return json Array of documents
*/
public function placeOrder(){
$cartItems = isset($_REQUEST['cartItems']) ? $_REQUEST['cartItems'] : [];
$orderDetails = isset($_REQUEST['orderDetails']) ? $_REQUEST['orderDetails'] : [];
echo json_encode($this->model->placeOrder($cartItems, $orderDetails), JSON_NUMERIC_CHECK);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
<?php
/**
* CoMarket controlls the actions for the shop
*/
class CoMarketController{
private $model;
function __construct(){
$this->model = new CoMarketModel();
}
/**
* get all packages taht can be sold
* @return json all packages that can be sold in web shop
*/
public function getShopPackages(){
$idCommercialLead = isset($_REQUEST['idCommercialLead']) ? $_REQUEST['idCommercialLead'] : 0;
$serach = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
echo json_encode($this->model->getShopPackages($idCommercialLead, 0, $serach), JSON_NUMERIC_CHECK);
}
/**
* get all comercial leads lined to the user
* @return json list of commercial leads
*/
public function getAllCommercialLeads(){
echo json_encode($this->model->getAllCommercialLeads(), JSON_NUMERIC_CHECK);
}
/**
* get web shop details for a package
* @return json package details
*/
public function getShopPackageDetails(){
$idCommercialLead = isset($_REQUEST['idCommercialLead']) ? $_REQUEST['idCommercialLead'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->getShopPackageDetails($idCommercialLead, $idPackage), JSON_NUMERIC_CHECK);
}
/**
* add items to cart
*/
public function addToCart(){
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idPrice = isset($_REQUEST['idPrice']) ? $_REQUEST['idPrice'] : 0;
$options = isset($_REQUEST['options']) ? $_REQUEST['options'] : '[]';
echo json_encode($this->model->addToCart($idPackage, $idPrice, $options));
}
}

View File

@@ -0,0 +1,446 @@
<?php
/**
* Data manipulation for the model
*/
class CoMarketModel{
const PACKAGE_TYPES = [
'ID_STANDARD_TYPE' => 1,
'ID_OPTION_TYPE' => 2,
'ID_ADDITONAL_TYPE' => 3
];
public function getShopPackages($idCommercialLead, $idPackage = 0, $search = ''){
global $database, $user;
$whereSql = "WHERE p.status='available' AND p.idPackageType=".self::PACKAGE_TYPES['ID_STANDARD_TYPE']." ";
$search = $database->escapeValue($search);
if($idPackage !== 0){
$whereSql .= " AND p.id=$idPackage";
}
if($search !== ''){
$searchValues = explode(' ', $search);
$packageCondition = '';
$descriptionCondition = '';
$referenceCondition = '';
$countryCondition = '';
foreach ($searchValues as $valueToSearch) {
if($valueToSearch !== ''){
$packageCondition .= "p.name like '%".$valueToSearch."%'"." OR ";
$descriptionCondition .= " p.description like '%".$valueToSearch."%'"." OR ";
$referenceCondition .= "p.reference='".$valueToSearch."' OR ";
$countryCondition .= "c.name='".$valueToSearch."' OR ";
}
}
$countryCondition = rtrim($countryCondition, ' OR ');
$whereSql .= " AND ( $packageCondition
$descriptionCondition
$referenceCondition
$countryCondition)";
}
$sql = "SELECT
p.id AS idPackage,
p.reference,
p.name,
p.photo,
p.photoPublicId,
p.description AS shortDescription,
price_selection.idCommercialLead,
c.name AS country,
c.code AS countryCode
FROM
".TABLES['packages']." p
INNER JOIN
".TABLES['countries']." c ON c.id = p.idCountry
INNER JOIN
(SELECT
idPackage,
plcl.idPaymentType,
plcl.idCommercialLead,
MAX(IFNULL(idCustomer, 0)) AS idCustomer
FROM
".TABLES['price_list_commercial_lead']." plcl
LEFT OUTER JOIN ".TABLES['customers']." cust
ON cust.id = plcl.idCustomer
WHERE
(cust.idUser = ".$user->getUserId()." OR cust.idUser IS NULL)
AND plcl.idCommercialLead = $idCommercialLead
GROUP BY plcl.idPackage , plcl.idPaymentType
) AS price_selection
ON price_selection.idPackage = p.id
INNER JOIN ".TABLES['price_list_commercial_lead']." plcl
ON plcl.idPackage = price_selection.idPackage
AND plcl.idPaymentType = price_selection.idPaymentType
AND plcl.idCommercialLead = price_selection.idCommercialLead
AND IFNULL(plcl.idCustomer, 0) = price_selection.idCustomer
AND plcl.visibleToCustomer = 1
INNER JOIN
(SELECT
proc.idCountry
FROM ".TABLES['processes']." proc
GROUP BY proc.idCountry
) proc_countries
ON proc_countries.idCountry=p.idCountry
$whereSql
GROUP BY p.id
ORDER BY p.name ASC";
$data = [];
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
if(strlen($row['shortDescription']) > 300 && $idPackage === 0){
$row['shortDescription'] = substr($row['shortDescription'], 0, 300) . '...';
}
if($row['photoPublicId']) {
$row['photo'] = IMAGE_URL . $row['photoPublicId'];
}
$data[] = $row;
}
return ['packages' => $data];
}
/**
* get all commercial leads linked to a customer
* @return Array list of commercial leads
*/
public function getAllCommercialLeads(){
global $database, $user;
$sql = "SELECT rclc.idCommercialLead,
cl.name as commercialLeadName,
u.mail as mail
FROM ".TABLES['rel_commercial_lead_customers']." rclc
INNER JOIN ".TABLES['customers']." c
ON c.id=rclc.idCustomer
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.id=rclc.idCommercialLead
INNER JOIN ".TABLES['users']." u
ON u.id = cl.idUser
WHERE rclc.isLinkEnabled=1 AND c.idUser=" . $user->getUserId();
return ['commercialLeads' => $database->fetchResultArray($sql)];
}
private function getCommercialLeadInfo($idCommercialLead){
global $database;
$sql = "SELECT
cl.name,
u.mail,
cl.phone
FROM ".TABLES['commercial_leads']." cl
INNER JOIN ".TABLES['users']." u
ON u.id = cl.idUser
WHERE cl.id=$idCommercialLead
";
return $database->fetchResultArray($sql);
}
/**
* get package options
* @param INT $idPackage id for the pacakge
* @param INT $idCommercialLead id for the comemrcial lead
* @return HashArray list of option packages grouped by group id
*/
private function getPackageOptions($idPackage, $idCommercialLead){
global $database;
$data = [];
$packages = new Packages();
$packageOptionPrices = $packages->getPricesForPackages($idCommercialLead, $idPackage, self::PACKAGE_TYPES['ID_OPTION_TYPE']);
$sql = "SELECT
rgo.idOptionPackage,
p.name AS optionName,
rgo.isDefault,
pog.id AS idGroup,
pog.name AS groupName,
p.description AS shortDescription
FROM ".TABLES['package_option_groups']." pog
INNER JOIN ".TABLES['rel_group_options']." rgo
ON rgo.idGroup=pog.id
INNER JOIN ".TABLES['packages']." p
ON p.id=rgo.idOptionPackage
WHERE pog.idPackage=$idPackage";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$idGroup = $row['idGroup'];
$data[$idGroup]['idGroup'] = $row['idGroup'];
unset($row['idGroup']);
$data[$idGroup]['groupName'] = $row['groupName'];
unset($row['groupName']);
$row['prices'] = isset($packageOptionPrices[$row['idOptionPackage']]) ? $packageOptionPrices[$row['idOptionPackage']] : [];
$data[$idGroup]['options'][] = $row;
}
return $data;
}
/**
* get package additional pacakges
* @param INT $idPackage id for the pacakge
* @param INT $idCommercialLead id for the comemrcial lead
* @return Array list of additonal packages
*/
private function getAdditionalPackages($idPackage, $idCommercialLead){
global $database;
$data = [];
$packages = new Packages();
$additionalPackagesPrices = $packages->getPricesForPackages($idCommercialLead, $idPackage, self::PACKAGE_TYPES['ID_ADDITONAL_TYPE']);
$sql = "SELECT
rap.idAdditionalPackage,
p.name AS packageName,
p.description AS shortDescription
FROM ".TABLES['rel_additional_packages']." rap
INNER JOIN ".TABLES['packages']." p
ON p.id=rap.idAdditionalPackage
WHERE rap.idPackage=$idPackage";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$row['prices'] = isset($additionalPackagesPrices[$row['idAdditionalPackage']]) ? $additionalPackagesPrices[$row['idAdditionalPackage']] : [];
$data[] = $row;
}
return $data;
}
/**
* get info for a pacakge that can be sold in the co-market
* @param INT $idCommercialLead id for the commetcial lead
* @param INT $idPackage id for the package
* @return HashArray pacakge details(country, prices, info, documents, options, additional package)
*/
public function getShopPackageDetails($idCommercialLead, $idPackage){
global $database, $user;
$countries = new Countries();
$packages = new Packages();
$packageDocuments = new PackageDocuments();
$idPackage = $database->escapeValue($idPackage);
$data = [];
$data['country'] = $countries->getCurrencyForPackage($idPackage);
$data['prices'] = $packages->getPricesForPackages($idCommercialLead, $idPackage, self::PACKAGE_TYPES['ID_STANDARD_TYPE']);
$data['prices'] = isset($data['prices'][$idPackage]) ? $data['prices'][$idPackage] : [];
if(empty( $data['prices'])){
return [];
}
$documents = $packageDocuments->getPackageDocuments($idPackage);
$data['documents'] = isset($documents[$idPackage]) ? $documents[$idPackage] : [];
$shopPackages = $this->getShopPackages($idCommercialLead, $idPackage);
$data['packageInfo'] = isset($shopPackages['packages'][0]) ? $shopPackages['packages'][0] : [];
$commerciaLeads = $this->getCommercialLeadInfo($idCommercialLead);
$data['commercialLead'] = isset($commerciaLeads[0]) ? $commerciaLeads[0] : [];
$data['groups'] = $this->getPackageOptions($idPackage, $idCommercialLead);
$data['additionalPackages'] = $this->getAdditionalPackages($idPackage, $idCommercialLead);
return $data;
}
/**
* insert new option when adding item to cart
* @param INT $idCart id for the cart
* @param Object $options options to be added
* @return INT number of inserted items
*/
private function insertOptionsToCart($idCart, $options){
global $database;
if($options === '[]' || empty((array) $options)){
return 0;
}
$sql = "INSERT INTO ".TABLES['web_shop_cart_extra_packages']."
(idCart, idExtraPackage)
VALUES ";
foreach ($options as $idOption => $idOptionValue) {
$idOptionValue = $database->escapeValue($idOptionValue);
$sql .= "($idCart, $idOptionValue),";
}
$sql = rtrim($sql, ",");
$query = $database->query($sql);
return $database->affectedRows();
}
/**
* add new items to the cart
* @param INT $idPackage id for the package
* @param INT $idPrice id for the price
* @return array action message
*/
public function addToCart($idPackage, $idPrice, $options){
global $database, $user;
$data = [];
if(!$idPackage || !$idPrice){
$err_mes = [
'code' => 'error',
'message' => 'INVALID_SELECTION'
];
$data['messages'][] = $err_mes;
return $data;
}
$idPackage = $database->escapeValue($idPackage);
$idPrice = $database->escapeValue($idPrice);
$idUser = $user->getUserId();
$sql = "SELECT plcl.idCommercialLead, availableCl.idCustomerInstance
FROM ".TABLES['price_list_commercial_lead']." plcl
INNER JOIN
(
SELECT rclc.idCommercialLead, rclc.id as idCustomerInstance
FROM ".TABLES['customers']." cust
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON cust.id=rclc.idCustomer AND rclc.isLinkEnabled=1
WHERE cust.idUser=$idUser
) availableCl
ON availableCl.idCommercialLead = plcl.idCommercialLead
WHERE plcl.id=$idPrice
LIMIT 1";
$customer = $database->fetchResultArray($sql);
if(count($customer) !== 1){
$err_mes = [
'code' => 'error',
'message' => 'INVALID_USER'
];
$data['messages'][] = $err_mes;
return $data;
}
$sql = "SELECT rclc.idCommercialLead
FROM ".TABLES['rel_commercial_lead_customers']." rclc
INNER JOIN ".TABLES['web_shop_cart']." wsc
ON wsc.idCustomerInstance=rclc.id
INNER JOIN ".TABLES['customers']." c
ON c.id=rclc.idCustomer
WHERE c.idUser=$idUser
LIMIT 1
";
$alreadySelectedCL = $database->fetchResultArray($sql);
if(count($alreadySelectedCL) > 0 && $alreadySelectedCL[0]['idCommercialLead'] !== $customer[0]['idCommercialLead']){
$err_mes = [
'code' => 'warning',
'message' => 'ONLY_ONE_CL'
];
$data['messages'][] = $err_mes;
return $data;
}
$sql = "SELECT
COUNT(DISTINCT idCountry) AS differentCountries
FROM
(SELECT DISTINCT
p.idCountry
FROM
".TABLES['web_shop_cart']." wsc
INNER JOIN ".TABLES['packages']." p
ON wsc.idPackage = p.id
WHERE
idCustomerInstance = ".$customer[0]['idCustomerInstance']." AND idUser = $idUser
UNION ALL
SELECT
p.idCountry
FROM
".TABLES['packages']." p
WHERE
p.id = $idPackage) countires";
$countriesCount = $database->fetchResultArray($sql)[0];
if(intval($countriesCount['differentCountries']) > 1){
$err_mes = [
'code' => 'warning',
'message' => 'ONLY_ONE_COUNTRY'
];
$data['messages'][] = $err_mes;
return $data;
}
$sqlCheckPackage = "
SELECT idPackage
FROM ".TABLES['web_shop_cart']."
WHERE idPackage = $idPackage
AND idCustomerInstance = ".$customer[0]['idCustomerInstance']."
AND idUser = $idUser
";
$result = $database->query($sqlCheckPackage);
if($database->numRows($result) > 0){
$err_mes = [
'code' => 'error',
'message' => 'PACKAGE_ALREADY_IN_CART'
];
$data['messages'][] = $err_mes;
return $data;
}
$sqlPackageInstance = "SELECT MAX(rpp.packageInstance) as maxInstance
FROM ".TABLES['rel_package_products']." rpp
WHERE rpp.idPackage=$idPackage";
$result = $database->fetchResultArray($sqlPackageInstance);
if(count($result) === 0){
$err_mes = [
'code' => 'error',
'message' => 'PACKAGE_ERROR'
];
$data['messages'][] = $err_mes;
return $data;
}
$maxPackageInstance = $result[0]['maxInstance'];
$sqlIns = "INSERT INTO ".TABLES['web_shop_cart']."
(idPackage, idCustomerInstance, idPrice, idUser, quantity, packageInstance)
VALUES($idPackage,
".$customer[0]['idCustomerInstance'].",
$idPrice,
$idUser,
1,
$maxPackageInstance)";
$query = $database->query($sqlIns);
$idCart = $database->getInsertId();
if($database->affectedRows() !== 1){
$err_mes = [
'code' => 'error',
'message' => 'PACKAGE_ALREADY_IN_CART'
];
$data['messages'][] = $err_mes;
return $data;
}
$insertedOptions = $this->insertOptionsToCart($idCart, $options);
if($insertedOptions){
$mes = [
'code' => 'success',
'message' => 'OPTIONS_ADDED'
];
$data['messages'][] = $mes;
}
$mes = [
'code' => 'success',
'message' => 'PACKAGE_ADDED'
];
$data['messages'][] = $mes;
return $data;
}
}

View File

@@ -0,0 +1,75 @@
<?php
class ClCustomers{
/**
* get customers list linked to the commercial lead
* @return Array list of customers linked to a commercial lead
*/
public function getComercialLeadCustomers(){
global $database, $user;
$idUser = $user->getUserId();
$data = [];
$sql = "SELECT
rclc.id as idCustomerInstance,
c.name AS customerName,
rclc.idOrderType,
IF(u.idCompany = clCompany.idCompany, 1, 0) AS isSameCompanyAsCl
FROM
".TABLES['customers']." c
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.idCustomer=c.id AND isLinkEnabled=1
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.id=rclc.idCommercialLead
INNER JOIN ".TABLES['users']." u
ON u.id = c.idUser
INNER JOIN
(SELECT
us.idCompany,
us.id
FROM
".TABLES['users']." us
WHERE us.id = $idUser) clCompany
ON clCompany.id = cl.idUser
WHERE cl.idUser=$idUser
";
return $database->fetchResultArray($sql);
}
public function getClCustomerInfo($idCommercialLead){
global $database, $user;
$idUser = $user->getUserId();
$data = [];
$sql = "SELECT
rclc.id as idCustomerInstance,
c.name AS customerName,
c.id AS idCustomer,
rclc.idOrderType,
IF(u.idCompany = clCompany.idCompany, 1, 0) AS isSameCompanyAsCl
FROM
".TABLES['customers']." c
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.idCustomer=c.id AND isLinkEnabled=1
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.id=rclc.idCommercialLead
INNER JOIN ".TABLES['users']." u
ON u.id = c.idUser
INNER JOIN
(SELECT
us.idCompany,
cl.id
FROM
".TABLES['users']." us
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.idUser=us.id
WHERE cl.id = $idCommercialLead) clCompany
ON clCompany.id = cl.id
WHERE c.idUser=$idUser AND rclc.idCommercialLead=$idCommercialLead";
$query = $database->query($sql);
$data = $database->fetchArray($query);
return $data;
}
}

View File

@@ -0,0 +1,144 @@
<?php
class OrderType{
const ORDER_TYPES = [
'commercial_lead' => 1,
'reseller' => 2
];
/**
* returns all the invoice processes existing in the application
* @return Array all the invoice processes from the application
*/
public function getOrderTypes() {
global $database;
$sql = "SELECT
id AS idOrderType,
name,
details
FROM
".TABLES['order_types'];
return $database->fetchResultArray($sql);
}
/**
* save Default Order Type
* @param INT $defaultIdOrderType id for default order type
* @return Array update message
*/
public function saveDefaultOrderType($defaultIdOrderType){
global $database, $user;
$idUser = $user->getUserId();
$data = [];
$defaultIdOrderType = $database->escapeValue($defaultIdOrderType);
if(!$defaultIdOrderType){
$data['messages'][] = [
'code' => 'error',
'message' => 'DEFAULT_VALUE_REQUIRED'
];
return $data;
}
$sql = "UPDATE ".TABLES['commercial_leads']."
SET defaultIdOrderType=$defaultIdOrderType
WHERE idUser=$idUser";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'DEFAULT_VALUE_UPDATED'
];
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}
return $data;
}
/**
* save Customers Order Types
* @param Object $customers list of customers containg alos the id for order type
* @return Array update message
*/
public function saveCustomersOrderTypes($customers){
global $database, $user;
$idUser = $user->getUserId();
$data = [];
$customers = json_decode($customers);
$idCustomerInstances = [];
foreach ($customers as $customer) {
if($customer->idOrderType){
$idCustomerInstances[] = $database->escapeValue($customer->idCustomerInstance);
}
}
$totalCustomers = count($idCustomerInstances);
$customerList = $totalCustomers > 0 ? implode($idCustomerInstances, ',') : '0';
$sql = "SELECT COUNT(rclc.id) AS validCustomers
FROM ".TABLES['rel_commercial_lead_customers']." rclc
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.id=rclc.idCommercialLead
WHERE cl.idUser=$idUser AND rclc.id IN($customerList) ";
$query = $database->query($sql);
$row = $database->fetchArray($query);
if($row['validCustomers'] != $totalCustomers){
$data['messages'][] = [
'code' => 'error',
'message' => 'NOT_AUTHORIZED'
];
return $data;
}
$uppdated = 0;
foreach ($customers as $customer) {
if($customer->idOrderType){
$customer->idOrderType = $database->escapeValue($customer->idOrderType);
$customer->idCustomerInstance = $database->escapeValue($customer->idCustomerInstance);
$sql = "UPDATE ".TABLES['rel_commercial_lead_customers']."
SET idOrderType=".$customer->idOrderType."
WHERE id=".$customer->idCustomerInstance;
$query = $database->query($sql);
$uppdated += $database->affectedRows($query);
}
}
if($uppdated > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'ORDER_TYPES_UPDATED'
];
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}
return $data;
}
public function getCLDefaultOrderType($idCommercialLead = 0){
global $database, $user;
$whereSql = $idCommercialLead ? "cl.id=$idCommercialLead" : "cl.idUser=".$user->getUserId();
$sql = "SELECT
cl.defaultIdOrderType
FROM ".TABLES['commercial_leads']." cl
WHERE $whereSql
LIMIT 1";
$query = $database->query($sql);
$row = $database->fetchArray($query);
return $row['defaultIdOrderType'];
}
}

View File

@@ -0,0 +1,39 @@
<?php
class DashboardsController{
private $model;
function __construct(){
$this->model = new DashboardsModel();
}
/**
* get data required for order central gadget
* @return json orders info
*/
public function getOrderCentralInfo(){
$viewAllOrders = isset($_REQUEST['viewAllOrders']) ? $_REQUEST['viewAllOrders'] : false;
$filters = isset($_REQUEST['filters']) ? $_REQUEST['filters'] : '';
$sortBy = isset($_REQUEST['sortBy']) ? $_REQUEST['sortBy'] : '';
echo json_encode($this->model->getOrderCentralInfo($viewAllOrders, $filters, $sortBy), JSON_NUMERIC_CHECK);
}
/**
* get selected dashbord info
* @return json info and gadgets for selected dashboards
*/
public function getMyDashboard(){
$idDashboard = isset($_REQUEST['myDashboard']) ? $_REQUEST['myDashboard'] : 0;
echo json_encode($this->model->getMyDashboard($idDashboard));
}
/**
* get data required for the enxt action gadget
* @return json next actions info
*/
public function getNextActionsInfo(){
$filters = isset($_REQUEST['filters']) ? $_REQUEST['filters'] : '';
$sortBy = isset($_REQUEST['sortBy']) ? $_REQUEST['sortBy'] : '';
echo json_encode($this->model->getNextActionsInfo($filters, $sortBy), JSON_NUMERIC_CHECK);
}
}
?>

View File

@@ -0,0 +1,278 @@
<?php
class DashboardsModel{
/**
* get all gadgets in a dashborad
* @param INT $idDashboard id of the dashborad
* @return Array array of gadgets
*/
private function getGadgets($idDashboard){
global $database;
$sql = "SELECT
g.id AS idGadget,
g.name,
g.module,
rdg.position
FROM ".TABLES['gadgets']." g
INNER JOIN ".TABLES['rel_dashboard_gadgets']." rdg
ON rdg.idGadget=g.id
WHERE rdg.idDashboard=$idDashboard
ORDER by rdg.position";
return $database->fetchResultArray($sql);
}
/**
* get information to show for dashborad view
* @param INT $idDashboard id of the dashborad
* @return HASHARRAY dahsborad info
*/
public function getMyDashboard($idDashboard){
global $database, $user;
$data = [];
$whereSql = $user->getUserType() === USER_TYPES['BROKER']
? "(d.idUser=".$user->getUserId()." OR d.visibility='public')"
: "(d.idUser=".$user->getUserId()." OR (d.visibility='public' AND d.idUserType=".$user->getIdUserType()."))";
$isOwner = $user->getUserType() === USER_TYPES['BROKER']
? "1 AS isOwner"
: "CASE WHEN d.idUser=".$user->getUserId()." THEN 1 ELSE 0 END AS isOwner";
$idDashboard = intval($database->escapeValue($idDashboard));
if($idDashboard !== 0){
$whereSql .= "AND d.id=$idDashboard";
}
$sql = "SELECT d.id AS idDashboard,
d.name,
$isOwner
FROM ".TABLES['dashboards']." d
WHERE $whereSql
ORDER BY d.lastUpdated DESC
LIMIT 1";
$data['info'] = $database->fetchResultArray($sql);
$data['info'] = isset($data['info'][0]) ? $data['info'][0] : [];
if(!empty($data['info'])){
$data['gadgets'] = $this->getGadgets($data['info']['idDashboard']);
}else{
return $this->getMyDashboard(0);
}
return $data;
}
/**
* get information for next actions gadget
* @param Array $filters array of filters to be applied
* @return Array array with next actions
*/
public function getNextActionsInfo($filters, $sortBy){
global $database, $user;
$filters = json_decode($filters);
$whereSql = UtilsModel::setFilterSql($filters);
$orderBySql = UtilsModel::setOrderBySql($sortBy);
$data = [];
if(!$orderBySql){
$orderBySql = "idOrder DESC";
}
if($user->getUserType() === USER_TYPES['BROKER']){
$sql = "SELECT * FROM(
SELECT
DISTINCT o.id as idOrder,
o.orderNumber,
ps.shortDesc as stepAction,
'in-progress' AS status
FROM ".TABLES['rel_order_process_step']." rops
INNER JOIN ".TABLES['orders']." o
ON o.id=rops.idOrder
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.id=rops.idProcessStep
INNER JOIN ".TABLES['process_step']." ps
ON ps.id=rps.idStep
WHERE rops.status='in-progress'
) actions
WHERE $whereSql
ORDER BY $orderBySql
LIMIT 7";
$data = $database->fetchResultArray($sql);
}else{
$sqlTemp= "CREATE TEMPORARY TABLE temp_next_actions AS (
SELECT * FROM(
SELECT
o.id as idOrder,
o.orderNumber,
ps.shortDesc as stepAction,
ps.idActionCode
FROM ".TABLES['rel_order_process_step']." rops
INNER JOIN ".TABLES['orders']." o
ON o.id=rops.idOrder
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id=o.idCustomerInstance
INNER JOIN ".TABLES['customers']." c
ON c.id=rclc.idCustomer
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.id=rops.idProcessStep
INNER JOIN ".TABLES['process_step']." ps
ON ps.id=rps.idStep
WHERE c.idUser=" .$user->getUserId(). " AND rops.status='in-progress' AND ps.idActionCode IN(4,6,8)
) actions
WHERE $whereSql
ORDER BY $orderBySql
LIMIT 7
)";
$query = $database->query($sqlTemp);
//questionnaiire validation
$sql = "SELECT
tna.idOrder,
tna.orderNumber,
tna.stepAction,
rod.validation as status
FROM temp_next_actions tna
INNER JOIN ".TABLES['rel_order_documents']." rod
ON rod.idOrder=tna.idOrder
WHERE tna.idActionCode=4 AND rod.validation='invalid'";
$data = $database->fetchResultArray($sql);
//customer acceptance
$sql = "SELECT
tna.idOrder,
tna.orderNumber,
tna.stepAction,
'not-accepted' as status
FROM temp_next_actions tna
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rop.idOrder=tna.idOrder
WHERE tna.idActionCode=6 AND rop.customerAccepted=0";
$data = array_merge($data, $database->fetchResultArray($sql) );
//schedule meeting
$sql = "SELECT
DISTINCT tna.idOrder,
tna.orderNumber,
tna.stepAction,
'pending' as status
FROM temp_next_actions tna
INNER JOIN ".TABLES['rel_order_scheduled_dates']." rosd
ON rosd.idOrder=tna.idOrder
WHERE tna.idActionCode=8 AND rosd.isDateConfirmed=0";
$data = array_merge($data, $database->fetchResultArray($sql) );
$delSql = "DROP TABLE temp_next_actions";
$query = $database->query($delSql);
}
return $data;
}
/**
* get information for the order central gadget
* @param Bool $viewAllOrders true if the user is company admin and checks the view all orders
* @param Array $filters array of filters to be applied
* @return Array array with orders info
*/
public function getOrderCentralInfo($viewAllOrders, $filters, $sortBy){
global $database, $user;
$filters = json_decode($filters);
$sortBy = json_decode($sortBy);
$whereSql = UtilsModel::setFilterSql($filters);
$orderBySql = UtilsModel::setOrderBySql($sortBy);
$extraJoin = '';
$extraWhere = '';
$extraHeaders = '';
$countries = new Countries();
$userType = $user->getUserType();
$data = [];
$idUser = $user->getUserId();
if(!$orderBySql){
$orderBySql = "idOrder DESC";
}
if($userType === USER_TYPES['BROKER']) {
$extraWhere = "AND (
b.idUser = $idUser
OR o.assignedTo IS NULL
)";
}
if($userType === USER_TYPES['CUSTOMER']) {
$extraJoin = "INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id = o.idCustomerInstance
INNER JOIN ".TABLES['customers']." c
ON rclc.idCustomer = c.id";
if($viewAllOrders === 'true') {
$extraHeaders = "c.name AS placedBy,";
$extraJoin .= " INNER JOIN ".TABLES['users']." u
ON u.id = c.idUser
INNER JOIN ".TABLES['users']." uc
ON uc.idCompany = u.idCompany
AND uc.id = $idUser";
} else {
$extraJoin .= " AND c.idUser = $idUser";
}
}
if($userType === USER_TYPES['COMMERCIAL_LEAD']) {
$extraJoin = "INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id = o.idCustomerInstance
INNER JOIN ".TABLES['commercial_leads']." cl
ON rclc.idCommercialLead = cl.id";
if($viewAllOrders === 'true') {
$extraHeaders = "cl.name AS placedBy,";
$extraJoin .= " INNER JOIN ".TABLES['users']." u
ON u.id = cl.idUser
INNER JOIN ".TABLES['users']." ucl
ON ucl.idCompany = u.idCompany
AND ucl.id = $idUser";
} else {
$extraJoin .= " AND cl.idUser = $idUser";
}
}
if($userType === USER_TYPES['SUPPLIER']) {
$extraJoin = "INNER JOIN ".TABLES['rel_package_products']." rpp
ON rpp.idPackage=rop.idPackage AND rop.packageInstance=rpp.packageInstance
INNER JOIN ".TABLES['suppliers_countries_products']." scp
ON scp.idProduct=rpp.idProduct
INNER JOIN ".TABLES['suppliers']." s
ON s.id=scp.idSupplier
AND s.idUser = $idUser";
}
$sql = "SELECT * FROM(
SELECT o.id AS idOrder,
o.orderNumber,
$extraHeaders
DATE_FORMAT(o.orderDate, '%D %b, %Y') AS orderDate,
o.reference,
IF(b.name IS NULL, 'unassigned', b.name) AS assignedTo,
SUM(rop.packageFixedPrice * rop.units) AS fixedPrice,
SUM((rop.packageRecuringPrice * rop.units) + (rop.packageServicePrice * rop.units)) AS recurringPrice,
o.status
FROM ".TABLES['orders']." o
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rop.idOrder=o.id
$extraJoin
LEFT JOIN ".TABLES['brokers']." b
ON o.assignedTo = b.id
WHERE o.status!='production' AND o.status!='canceled' AND o.status!='end-of-life'
$extraWhere
GROUP BY o.id
) orders
WHERE $whereSql
ORDER BY $orderBySql
LIMIT 5";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$row['currency'] = $countries->getCurrencyForOrder($row['idOrder']);
$data[] = $row;
}
return $data;
}
}
?>

View File

@@ -0,0 +1,35 @@
<?php
class FinancingController{
private $model;
function __construct(){
$this->model = new FinancingModel();
}
/**
* get interest rate
* @return json value for intereset rate
*/
public function getInterestRate(){
echo json_encode($this->model->getInterestRate(), JSON_NUMERIC_CHECK);
}
/**
* get interest rate for customers
* @return json values for interest rate for each customer
*/
public function getInterestRateForCustomers(){
echo json_encode($this->model->getInterestRateForCustomers(), JSON_NUMERIC_CHECK);
}
/**
* save interest rate
* @return json update message
*/
public function saveInterestRate(){
$interestRate = isset($_REQUEST['interestRate']) ? $_REQUEST['interestRate'] : 0;
echo json_encode($this->model->saveInterestRate($interestRate));
}
}

View File

@@ -0,0 +1,31 @@
<?php
class FinancingModel{
/**
* get interest rate
* @return HashArray interest rate value
*/
public function getInterestRate(){
$interestRate = new InterestRate();
return $interestRate->getInterestRate();
}
/**
* get interest rate for customers
* @return HashArray values for interest rate for each customer
*/
public function getInterestRateForCustomers(){
$interestRate = new InterestRate();
return $interestRate->getInterestRateForCustomers();
}
/**
* save interest rate
* @param Float $interestRateValue interest rate value
* @return Array update message
*/
public function saveInterestRate($interestRateValue){
$interestRate = new InterestRate();
return $interestRate->saveInterestRate($interestRateValue);
}
}

View File

@@ -0,0 +1,154 @@
<?php
class InterestRate{
const SYSTEM_FINANCING_RATE_ID = 1;
/**
* get interest rate
* @return HashArray interest rate value
*/
public function getInterestRate(){
global $database;
$data = [];
$sql = "SELECT
f.interestRate
FROM ".TABLES['financing']." f
WHERE f.id=".self::SYSTEM_FINANCING_RATE_ID;
$query = $database->query($sql);
$row = $database->fetchArray($query);
$data['interestRate'] = isset($row['interestRate']) ? $row['interestRate'] : 0;
return $data;
}
/**
* get interest rate for each customer
* @return HashArray interest rate value for every customer in the system
*/
public function getInterestRateForCustomers(){
global $database;
$data = [];
$interestRate = $this->getInterestRate()['interestRate'];
$sql = "SELECT
rcd.discount,
rcd.idCustomer
FROM
".TABLES['rel_customer_discount']." rcd";
$query = $database->query($sql);
while($row = $database->fetchArray($query)) {
$data[$row['idCustomer']] = $interestRate - $row['discount'];
}
return $data;
}
/**
* save interest rate
* @param Float $interestRateValue interest rate value
* @return Array update message
*/
public function saveInterestRate($interestRate){
global $database;
$interestRate = $database->escapeValue($interestRate);
$data = [];
if(!$interestRate){
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_INTEREST_RATE'
];
return $data;
}
$checkMessage = $database->invalidNumber('interestRate', $interestRate, 0, 100);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
$sql = "UPDATE ".TABLES['financing']."
SET interestRate = $interestRate
WHERE id=".self::SYSTEM_FINANCING_RATE_ID;
$query = $database->query($sql);
$data['messages'][] = [
'code' => 'success',
'message' => 'INTEREST_RATE_UPDATED'
];
return $data;
}
/**
* get customers discounts
* @return HashArray interest rate value
*/
public function getCustomersAndDiscount() {
global $database;
$data = $this->getInterestRate();
$sql = "SELECT
c.id AS idCustomer,
c.name,
IFNULL(rcd.discount, 0) AS discount
FROM
".TABLES['customers']." c
LEFT JOIN ".TABLES['rel_customer_discount']." rcd
ON c.id = rcd.idCustomer";
$data['customers'] = $database->fetchResultArray($sql);
return $data;
}
/**
* save discount for customer - financing
* @param Array $details id of the customer and the discount applied for each
* @return Array update message
*/
public function saveCustomersDiscount($details) {
global $database;
$interestRate = $this->getInterestRate()['interestRate'];
$insertValues = '';
$affectedRows = 0;
$data = [];
if(!count($details)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'CUSTOMERS_DISCOUNT_EMPTY'
];
return $data;
}
foreach($details as $customerDiscounts) {
$discount = floatval($customerDiscounts['discount']);
if($discount > $interestRate || $discount < 0) {
$data['messages'][] = [
'code' => 'warning',
'message' => 'DISCOUNT_NOT_VALID',
'key' => $customerDiscounts['name']
];
} else {
$sql = "INSERT INTO ".TABLES['rel_customer_discount']."
(idCustomer, discount)
VALUES (".$customerDiscounts['idCustomer'].", '$discount')
ON DUPLICATE KEY
UPDATE
discount = '$discount'";
$row = $database->query($sql);
$affectedRows += $database->affectedRows();
}
}
if($affectedRows) {
$data['messages'][] = [
'code' => 'success',
'message' => 'DISCOUNT_UPDATED'
];
}
return $data;
}
}

View File

@@ -0,0 +1,414 @@
<?php
class AddressHelper{
/**
* returns the delivery address information for the user logged in
* @return Array delivery address
*/
public function getDeliveryAddress() {
global $database, $user;
$sqlDelivery = "SELECT
da.id,
da.detailedAddress AS detailedAddress,
da.city AS city,
da.zip AS zipCode,
co.name AS countryName,
co.id AS idCountrySelected
FROM
".TABLES['customers']." c
INNER JOIN ".TABLES['delivery_addresses']." da
ON da.idUser = c.idUser
INNER JOIN ".TABLES['countries']." co
ON co.id = da.idCountry
WHERE c.idUser = ".$user->getUserId()."
ORDER BY da.id DESC
";
return $database->fetchResultArray($sqlDelivery);
}
/**
* returns the billing address information for the user logged in
* @return Array billing address info
*/
public function getBillingAddress() {
global $database, $user;
$sqlBillingAddress = "SELECT
bi.id AS id,
bi.firstName AS firstName,
bi.lastName AS lastName,
bi.invoiceMail AS invoiceMail,
bi.idCountry AS idCountrySelected,
bi.detailedAddress AS detailedAddress,
bi.city AS city,
co.name AS countryName,
bi.zip AS zipCode
FROM
".TABLES['customers']." c
INNER JOIN ".TABLES['billing_information']." bi
ON bi.idUser = c.idUser
INNER JOIN ".TABLES['countries']." co
ON co.id = bi.idCountry
WHERE c.idUser = ".$user->getUserId()."
ORDER BY bi.id DESC
";
return $database->fetchResultArray($sqlBillingAddress);
}
/**
* check the owner for the address
* @param INT $idProfileAddress id for delivery address
* @return boolean returns ture if the users is the address owner
*/
private function checkAddressOwner($idProfileAddress){
global $database, $user;
$sql = "SELECT da.idUser
FROM ".TABLES['delivery_addresses']." da
WHERE da.id=$idProfileAddress AND da.idUser=".$user->getUserId();
$query = $database->query($sql);
return $database->numRows($query) > 0;
}
/**
* remove delivery address
* @param INT $idProfileAddress id delivery address
* @return Array update message
*/
public function removeProfileAddress($idProfileAddress){
global $database, $user;
$idProfileAddress = $database->escapeValue($idProfileAddress);
$data = [];
if(!$idProfileAddress){
$err_mes = [
'code' => 'error',
'message' => 'NO_ADDRESS_SELECTED'
];
$data['messages'][] = $err_mes;
return $data;
}
if(!$this->checkAddressOwner($idProfileAddress)){
$err_mes = [
'code' => 'error',
'message' => 'NOT_ADDRESS_OWNER'
];
$data['messages'][] = $err_mes;
return $data;
}
$sql = "DELETE FROM ".TABLES['delivery_addresses']."
WHERE id=$idProfileAddress ";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$mes = [
'code' => 'success',
'message' => 'ADDRESS_REMOVED'
];
}else{
$mes = [
'code' => 'error',
'message' => 'ADDRESS_ERROR'
];
}
$data['messages'][] = $mes;
return $data;
}
/**
* validate data for saving address
* @param Object $info address information
* @return Array validation messages or empty if data is valid
*/
private function validateAddressData($info, $type = 'profileAddress'){
global $database;
$data = [];
foreach (get_object_vars($info) as $key => $value) {
$info->{$key} = $database->escapeValue($value);
}
if(!isset($info->idCountrySelected) || empty($info->idCountrySelected)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_COUNTRY'
];
return $data;
}
if(!isset($info->city) || empty($info->city)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_CITY'
];
return $data;
}
$checkMessage = $database->invalidLength('city', $info->city, 100);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if(!isset($info->detailedAddress) || empty($info->detailedAddress)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_ADDRESS'
];
return $data;
}
$checkMessage = $database->invalidLength('detailedAddress', $info->detailedAddress, 500);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if(!isset($info->zipCode) || empty($info->zipCode)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_ZIP'
];
return $data;
}
$checkMessage = $database->invalidLength('zipCode', $info->zipCode, 20);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if($type === 'billingAddress'){
if(isset($info->invoiceMail) && !empty($info->invoiceMail)) {
$checkMessage = $database->invalidLength('invoiceMail', $info->invoiceMail, 300);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if(!filter_var($info->invoiceMail, FILTER_VALIDATE_EMAIL)){
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_INVOICE_MAIL'
];
}
}
}
return $data;
}
/**
* save delivery address
* @param Object $profileAddress delivery address information
* @return Array update message
*/
public function saveProfileAddress($profileAddress){
global $database, $user;
$profileAddress = json_decode($profileAddress);
$idUser = $user->getUserId();
$data = [];
$userHelper = new UsersHelper();
if(!$profileAddress){
$err_mes = [
'code' => 'error',
'message' => 'INVALID_PROFILE_ADDRESS'
];
$data['messages'][] = $err_mes;
return $data;
}
if(!$userHelper->checkRightsToEdit($idUser)){
$err_mes = [
'code' => 'error',
'message' => 'INVALID_USER'
];
$data['messages'][] = $err_mes;
return $data;
}
$checkMessage = $this->validateAddressData($profileAddress);
if(!empty($checkMessage)){
return $checkMessage;
}
$idAddress = isset($profileAddress->id) ? $profileAddress->id : 'null';
$sql = "INSERT INTO ".TABLES['delivery_addresses']." (id, idUser, idCountry, city, detailedAddress, zip)
VALUES(".$idAddress.",
".$idUser.",
".$profileAddress->idCountrySelected.",
'".$profileAddress->city."',
'".$profileAddress->detailedAddress."',
'".$profileAddress->zipCode."')
ON DUPLICATE KEY UPDATE
idCountry= VALUES(idCountry),
city= VALUES(city),
detailedAddress=VALUES(detailedAddress),
zip=VALUES(zip)";
$query = $database->query($sql);
if($database->affectedRows()) {
$mes = [
'code' => 'success',
'message' => 'PROFILE_ADDRESS_UPDATED'
];
$data['messages'][] = $mes;
}else{
$mes = [
'code' => 'warning',
'message' => 'PROFILE_ADDRESS_NOT_CHANGED'
];
$data['messages'][] = $mes;
}
return $data;
}
/**
* check owner for billing address
* @param INT $idBillingAddress id for billing address
* @return Boolean true if use has rights to modify the billing address
*/
private function checkBillingAddressOwner($idBillingAddress){
global $database, $user;
$sql = "SELECT bi.idUser
FROM ".TABLES['billing_information']." bi
WHERE bi.id=$idBillingAddress AND bi.idUser=".$user->getUserId();
$query = $database->query($sql);
return $database->numRows($query) > 0;
}
/**
* remove billing address
* @param INT $idBillingAddress billing address information
* @return Array update message
*/
public function removeBillingAddress($idBillingAddress){
global $database, $user;
$idBillingAddress = $database->escapeValue($idBillingAddress);
$data = [];
if(!$idBillingAddress){
$err_mes = [
'code' => 'error',
'message' => 'NO_ADDRESS_SELECTED'
];
$data['messages'][] = $err_mes;
return $data;
}
if(!$this->checkBillingAddressOwner($idBillingAddress)){
$err_mes = [
'code' => 'error',
'message' => 'NOT_ADDRESS_OWNER'
];
$data['messages'][] = $err_mes;
return $data;
}
$sql = "DELETE FROM ".TABLES['billing_information']."
WHERE id=$idBillingAddress ";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$mes = [
'code' => 'success',
'message' => 'BILLING_ADDRESS_REMOVED'
];
$data['messages'][] = $mes;
}else{
$mes = [
'code' => 'error',
'message' => 'ADDRESS_ERROR'
];
$data['messages'][] = $mes;
}
return $data;
}
/**
* save billing address
* @param INT $idCompany id for company
* @param Object $billingAddress billing address information
* @return Array update message
*/
public function saveBillingAddress($idCompany, $billingAddress){
global $database, $user;
$billingAddress = json_decode($billingAddress);
$idCompany = $database->escapeValue($idCompany);
$idUser = $user->getUserId();
$data = [];
$userHelper = new UsersHelper();
if(!$billingAddress){
$err_mes = [
'code' => 'error',
'message' => 'INVALID_PROFILE_ADDRESS'
];
$data['messages'][] = $err_mes;
return $data;
}
$checkMessage = $this->validateAddressData($billingAddress, 'billingAddress');
if(!empty($checkMessage)){
return $checkMessage;
}
$idAddress = isset($billingAddress->id) ? $billingAddress->id : 'null';
$sql = "INSERT INTO ".TABLES['billing_information']." (id, idUser, idCountry, firstName, lastName, invoiceMail, city, detailedAddress, zip)
VALUES(".$idAddress.",
".$idUser.",
".$billingAddress->idCountrySelected.",
'".$billingAddress->firstName."',
'".$billingAddress->lastName."',
'".$billingAddress->invoiceMail."',
'".$billingAddress->city."',
'".$billingAddress->detailedAddress."',
'".$billingAddress->zipCode."')
ON DUPLICATE KEY UPDATE
idCountry= VALUES(idCountry),
firstName=VALUES(firstName),
lastName=VALUES(lastName),
invoiceMail=VALUES(invoiceMail),
city= VALUES(city),
detailedAddress=VALUES(detailedAddress),
zip=VALUES(zip)";
$query = $database->query($sql);
if($database->affectedRows()) {
$mes = [
'code' => 'success',
'message' => 'BILLING_ADDRESS_UPDATED'
];
$data['messages'][] = $mes;
}else{
$mes = [
'code' => 'warning',
'message' => 'BILLING_ADDRESS_NOT_CHANGED'
];
$data['messages'][] = $mes;
}
return $data;
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* Countries manages required data for countries
*/
class Countries {
/**
* get currency by package
* @param INT $idPackage id for the package
* @return String curency
*/
public function getCurrencyForPackage($idPackage){
global $database;
$sql = "SELECT c.currency
FROM ".TABLES['countries']." c
INNER JOIN ".TABLES['packages']." p
ON p.idCountry=c.id
WHERE p.id=$idPackage";
$row = $database->fetchResultArray($sql);
return !empty($row) ? $row[0] : '';
}
public function getCurrencyForOrder($idOrder){
global $database;
$data = [];
$sql = "SELECT
c.currency
FROM ".TABLES['countries']." c
INNER JOIN ".TABLES['packages']." p
ON p.idCountry=c.id
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rop.idPackage=p.id
WHERE rop.idOrder=$idOrder LIMIT 1";
$row = $database->fetchResultArray($sql);
return !empty($row) ? $row[0]['currency'] : '';
}
/**
* get all countries in the system
* @return Array list of countries
*/
public function getCountries(){
global $database;
$sql = "SELECT c.id AS idCountry,
c.name AS countryName
FROM ".TABLES['countries']." c";
return $database->fetchResultArray($sql);
}
}

View File

@@ -0,0 +1,17 @@
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Authorization");
header('Content-Type: application/json');
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
if($_SERVER['REQUEST_METHOD'] === 'OPTIONS'){
header('Access-Control-Max-Age: ' . JWT_MAX_LIFE);
header('Access-Control-Allow-Methods: OPTIONS, GET, POST');
die();
}
$route::call($module, $controller, $action);
?>

View File

@@ -0,0 +1,84 @@
<?php
class LoginController{
private $model;
function __construct(){
$this->model = new LoginModel();
}
/**
* get JWT Token for app
* @return json token
*/
public function getToken(){
global $user;
if(isset($_POST['login'])){
$login = $user->login($_POST['username'], $_POST['password'], true);
$login['userInfo'] = $user->getUserInfo();
$login['serverTime'] = time();
echo json_encode($login);
}else{
echo json_encode(['status' => 'fail', 'errorMessage' => 'invalid request']);
}
}
/**
* validate the token
* @return json status => status for token validation, errorMessage => error message
*/
public function validateToken(){
global $user;
if($user->isLoggedIn()){
$refreshToken = $user->getRefreshToken();
$message = ['status' => 'success', 'userInfo' => $user->getUserInfo(), 'refreshToken' => $refreshToken, 'serverTime' => time()];
}else{
$message = ['status' => 'fail', 'errorMessage' => $user->getErrorMessage()];
}
echo json_encode($message);
}
public function refreshToken(){
global $user;
$refreshToken = isset($_REQUEST['refreshToken']) ? $_REQUEST['refreshToken'] : '';
$lastActivity = isset($_REQUEST['lastActivity']) ? $_REQUEST['lastActivity'] : '1000';
$message = $user->refreshToken($refreshToken, $lastActivity);
$message['serverTime'] = time();
$message['userInfo'] = $user->getUserInfo();
echo json_encode($message);
}
/**
* get allowed modues for user type
* @return json modules array
*/
public function getModules(){
global $user, $route;
if($user->isLoggedIn()){
echo json_encode(['modules' => $route::getModules()]);
}else{
echo json_encode(['modules' => []]);
}
}
/**
* generate new token for user
* @return json update message
*/
public function forgotPassword(){
$mail = isset($_POST['mail']) ? $_POST['mail'] : '';
echo json_encode($this->model->forgotPassword($mail));
}
public function changePassword(){
$token = isset($_REQUEST['token']) ? $_REQUEST['token'] : '';
$passwords = [
'newPassword' => isset($_REQUEST['newPassword']) ? $_REQUEST['newPassword'] : '',
'confirmPassword' => isset($_REQUEST['confirmPassword']) ? $_REQUEST['confirmPassword'] : ''
];
echo json_encode($this->model->changePassword($token, $passwords));
}
}
?>

View File

@@ -0,0 +1,123 @@
<?php
class LoginModel{
const ID_TYPE_CUSTOMER = 2;
/**
* generatates a new password for the user given
* @param String $mail email of the user
* @return String confirtmation message
*/
public static function forgotPassword($mail) {
global $database;
$mail = $database->escapeValue($mail);
$now = new DateTime();
$now = $now->format('Y-m-d H:i:s');
$sql = "SELECT
u.username,
u.mail,
rut.idType AS idUserType,
ut.type AS type,
IF(
ADDTIME(u.tokenTS, '00:05') > '".$now."',
0,
1
) AS allowPasswordGeneration
FROM ".TABLES['users']." u
INNER JOIN ".TABLES['rel_user_type']." rut
ON rut.idUser=u.id
INNER JOIN ".TABLES['user_types']." ut
ON ut.id=rut.idType
WHERE mail = '".$mail."'";
$userInfo = $database->fetchResultArray($sql);
if(count($userInfo) == 0) {
$data['messages'][] = [
'code' => 'danger',
'message' => 'NO_USER'
];
return $data;
}
foreach ($userInfo as $info) {
if($info['allowPasswordGeneration'] == 1) {
$messageData = self::generateTokenForUserPassword(json_encode($info));
$data['messages'][] = [
'code' => 'success',
'message' => 'GENERATED_SUCCESSFULLY'
];
} else {
$data['messages'][] = [
'code' => 'warning',
'message' => 'CHANGE_LATER'
];
}
}
return $data;
}
/**
* generates a new random password for the user provided
* @param Array $userInfo contains username and password for the user of the password to change
* @return Array confirmation message
*/
public static function generateTokenForUserPassword($userInfo) {
global $database, $user;
$userInfo = (array) json_decode($userInfo);
$token = bin2hex(random_bytes(16));
$tokenTimestamp = new DateTime();
$sql = "UPDATE
".TABLES['users']." u
SET
u.token='".$token."',
u.tokenTS='".$tokenTimestamp->format('Y-m-d H:i:s')."'
WHERE u.username='".$database->escapeValue($userInfo['username'])."'";
$result = $database->query($sql);
if($database->affectedRows() == 1) {
$data['messages'][] = [
'code' => 'success',
'message' => 'PASSWORD_GENERATED'
];
} else {
$data['messages'][] = [
'code' => 'error',
'message' => 'ERROR_PASSWORD_GENERATED'
];
}
$data['messages'][] = UtilsModel::sendUserConfirmationMail($userInfo, $userInfo['mail'], 'generate', $token);
return $data;
}
/**
* change password for a user based on token
* @param String $token token required to change the password
* @param HashArray $passwords new password and confirm password array
* @return HashArray update message
*/
public function changePassword($token, $passwords){
global $user;
$data = [];
$confirmTokenMessage = $user->checkPasswordToken($token);
if($confirmTokenMessage !== 'success') {
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_CHANGE_TOKEN'
];
return $data;
}
$data = $user->resetPassword(json_encode($passwords));
return $data;
}
}

View File

@@ -0,0 +1,115 @@
<?php
class OrderProjects{
public function getOrderProjects($available = 1){
global $database;
$whereSql = intval($available) === 1 ? " AND op.isAvailable=1" : "";
$sql = "SELECT
op.id AS idProject,
op.name AS projectName,
op.isAvailable
FROM ".TABLES['order_projects']." op
WHERE 1=1 $whereSql";
return $database->fetchResultArray($sql);
}
private function validateProjectData($projectData){
global $database;
$data = [];
$checkMessage = $database->isEmpty('projectName', $projectData->projectName);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
$checkMessage = $database->invalidLength('projectName', $projectData->projectName, 100);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
return $data;
}
public function editOrderProject($projectData){
global $database;
$data = [];
$projectData = json_decode($projectData);
if(empty($projectData)){
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_DATA'
];
return $data;
}
$checkMessages = $this->validateProjectData($projectData);
if(!empty($checkMessages)){
return $checkMessages;
}
$sql = "UPDATE ".TABLES['order_projects']."
SET name='".$database->escapeValue($projectData->projectName)."',
isAvailable=".$database->escapeValue($projectData->isAvailable)."
WHERE id=".$database->escapeValue($projectData->idProject);
$query = $database->query($sql);
if($database->affectedRows() < 1){
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}else{
$data['messages'][] = [
'code' => 'success',
'message' => 'PROJECT_UPDATED'
];
}
return $data;
}
public function addOrderProject($projectData){
global $database;
$data = [];
$projectData = json_decode($projectData);
if(empty($projectData)){
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_DATA'
];
return $data;
}
$checkMessages = $this->validateProjectData($projectData);
if(!empty($checkMessages)){
return $checkMessages;
}
$sql = "INSERT INTO ".TABLES['order_projects']."
(name)
VALUES('".$database->escapeValue($projectData->projectName)."')";
$query = $database->query($sql);
if($database->affectedRows() < 1){
$data['messages'][] = [
'code' => 'warning',
'message' => 'INVALID_DATA'
];
}else{
$data['messages'][] = [
'code' => 'success',
'message' => 'PROJECT_ADDED'
];
}
return $data;
}
}

View File

@@ -0,0 +1,20 @@
<?php
class OrderProjectsController{
private $model;
function __construct(){
$this->model = new OrderProjectsModel();
}
public function getOrderProjects(){
$available = isset($_REQUEST['available']) ? $_REQUEST['available'] : 1;
echo json_encode($this->model->getOrderProjects($available), JSON_NUMERIC_CHECK);
}
public function addOrderProject(){
$projectData = isset($_REQUEST['projectData']) ? $_REQUEST['projectData'] : '[]';
echo json_encode($this->model->addOrderProject($projectData), JSON_NUMERIC_CHECK);
}
}

View File

@@ -0,0 +1,15 @@
<?php
class OrderProjectsModel{
public function getOrderProjects($available){
$orderProjectsHandler = new OrderProjects();
return $orderProjectsHandler->getOrderProjects($available);
}
public function addOrderProject($projectData){
$orderProjectsHandler = new OrderProjects();
return $orderProjectsHandler->addOrderProject($projectData);
}
}

View File

@@ -0,0 +1,184 @@
<?php
class CustomerAcceptance{
/**
* get info for customer acceptance
* @param INT $idOrder id for the order
* @param INT $idPackage id for the package
* @return Array custoemr acceptance info
*/
public function getCustomerAcceptance($idOrder){
global $database;
$idOrder = $database->escapeValue($idOrder);
$data = [];
$orderExtraActions = new orderExtraActions();
$sql = "SELECT o.id AS idOrder,
o.customerAccepted,
o.customerDeclineReason,
DATE_FORMAT(o.acceptanceDueDate, '%D %b, %y') as acceptanceDueDate,
o.acceptanceDueDate as acceptanceDueDateNoFormat
FROM ".TABLES['orders']." o
WHERE o.id=$idOrder";
$query = $database->query($sql);
if($database->numRows($query) > 0){
$row = $database->fetchArray($query);
$dueDate = new DateTime($row['acceptanceDueDateNoFormat']);
$now = time();
$timeDiff = ($dueDate->getTimestamp() - $now ) / (3600 *24);
$row['daysDiff'] = $timeDiff;
}
$data = $row;
$sql = "SELECT
d.id AS idDocument,
d.documentName,
d.extension,
rod.idOrder
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['rel_order_documents']." rod
ON rod.idDocument=d.id
WHERE rod.idOrder=$idOrder AND d.idDocumentType=".$orderExtraActions::DOCUMENT_TYPES['ID_ACCEPTANCE_DOC_TYPE'];
$query = $database->query($sql);
while($row = $database->fetchArray($query)) {
$data['acceptanceDocuments'][] = $row;
}
return $data;
}
/**
* get the number of acceptance documents uploaded
* @param INT $idOrder id for the order
* @return INT number of uploaded documents
*/
private function getAcceptanceDocumentsCount($idOrder){
global $database;
$orderExtraActions = new orderExtraActions();
$sql = "SELECT COUNT(idDocument) AS totalDocumentsUplaoded
FROM ".TABLES['rel_order_documents']." rod
INNER JOIN ".TABLES['documents']." d
ON d.id=rod.idDocument AND d.idDocumentType=".$orderExtraActions::DOCUMENT_TYPES['ID_ACCEPTANCE_DOC_TYPE']."
WHERE rod.idOrder=$idOrder
";
$query = $database->query($sql);
$row = $database->fetchArray($query);
return intval($row['totalDocumentsUplaoded']);
}
/**
* customer change acceptance status for a package
* @param INT $idOrder id for the order
* @param String $actionType accept or decline the installation
* @param String $declineReason the reason why the customer declined the installation
* @return Array update message
*/
public function acceptDeclineInstallation($idOrder, $actionType, $declineReason){
global $database;
$idOrder = $database->escapeValue($idOrder);
$actionType = trim($database->escapeValue($actionType));
$declineReason = trim($database->escapeValue($declineReason));
$data = [];
$customerAcceptanceStatus = 1;
$successMessage = 'INSTALLATION_ACCEPTED';
if($actionType === 'decline') {
if(!$declineReason) {
$data['messages'][] = [
'code' => 'error',
'message' => 'DECLINE_REASON_EMPTY'
];
return $data;
}
$customerAcceptanceStatus = -1;
$successMessage = 'INSTALLATION_DECLINED';
}else{
$uploadedDocuments = $this->getAcceptanceDocumentsCount($idOrder);
if($uploadedDocuments === 0){
$data['messages'][] = [
'code' => 'error',
'message' => 'ACCEPTANCE_NOT_UPLOADED'
];
return $data;
}
}
$sql = "UPDATE ".TABLES['orders']."
SET customerAccepted=$customerAcceptanceStatus,
customerDeclineReason='$declineReason'
WHERE id=$idOrder";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => $successMessage
];
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'ACCEPTANCE_NOT_UPDATED'
];
}
return $data;
}
/**
* upload customer acceptance document
* @param INT $idOrder id for the order
* @param FILE $file file to be uploaded
* @return Array upload status
*/
public function uploadAcceptanceDocument($idOrder, $file){
global $database, $user;
$orderExtraActions = new orderExtraActions();
$idOrder = $database->escapeValue($idOrder);
$fileManager = new FileManager();
$sql = "SELECT MAX(d.id)+1 AS maxIdDocument
FROM ".TABLES['documents']." d";
$maxId = $database->fetchResultArray($sql);
$maxIdDocument = $maxId && $maxId[0] && $maxId[0]['maxIdDocument'] ? $maxId[0]['maxIdDocument'] : 1;
$sql = "SELECT o.orderNumber
FROM orders o
WHERE id=$idOrder";
$query = $database->query($sql);
$row = $database->fetchArray($query);
$documentName = 'customerAcceptance_'.$row['orderNumber'].'_' . $maxIdDocument;
$uploadedBy = $user->getUserId();
$data = $fileManager->uploadFile($file, $orderExtraActions::DOCUMENT_TYPES['ID_ACCEPTANCE_DOC_TYPE'], $documentName, $uploadedBy);
if(isset($data['messages'])){
return $data;
}
$idDocument = $data['idDocument'];
$sql = "INSERT INTO ".TABLES['rel_order_documents']."
(idOrder, idDocument, validation)
VALUES($idOrder, $idDocument, 'not-validated')";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'FILE_UPLOADED'
];
}else{
$data['messages'][] = [
'code' => 'error',
'message' => 'NOT_LINKED_TO_ORDER'
];
}
return $data;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,100 @@
<?php
class OrderDocuments{
private function getProductDocuments($idOrder){
global $database, $user;
$whreSql = "";
$data = [];
if($user->getUserType() !== USER_TYPES['BROKER']){
$whreSql = " AND visibleToCustomer=1";
}
$sql = "SELECT
d.id AS idDocument,
d.documentName,
d.documentPath,
d.extension,
dt.type AS documentType,
rpp.idPackage,
rpd.idProduct
FROM ".TABLES['rel_product_documents']." rpd
INNER JOIN ".TABLES['documents']." d
ON d.id=rpd.idDocument
INNER JOIN ".TABLES['document_types']." dt
ON dt.id=d.idDocumentType
INNER JOIN ".TABLES['rel_package_products']." rpp
ON rpp.idProduct=rpd.idProduct
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rop.idPackage=rpp.idPackage AND rop.packageInstance=rpp.packageInstance
WHERE rop.idOrder=$idOrder $whreSql
";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idPackage']][] = $row;
}
return $data;
}
/**
* get all docuemnts linked to an order
* @param INT $idOrder id for the order
* @return Array list of documetns for an order grouped by package id
*/
public function getOrderDocuments($idOrder){
global $database;
$data = [];
$sql = "SELECT
d.id AS idDocument,
d.documentName,
d.documentPath,
d.extension,
dt.type AS documentType,
dt.folderName AS documentTypeName,
IFNULL(rod.idPackage, 0) as idPackage
FROM ".TABLES['rel_order_documents']." rod
INNER JOIN ".TABLES['documents']." d
ON d.id=rod.idDocument
INNER JOIN ".TABLES['document_types']." dt
ON dt.id=d.idDocumentType
WHERE rod.idOrder=$idOrder
UNION all
SELECT
d.id AS idDocument,
d.documentName,
d.documentPath,
d.extension,
dt.type AS documentType,
dt.folderName AS documentTypeName,
rpd.idPackage
FROM ".TABLES['rel_package_documents']." rpd
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rop.idPackage=rpd.idPackage
INNER JOIN ".TABLES['documents']." d
ON d.id=rpd.idDocument
INNER JOIN ".TABLES['document_types']." dt
ON dt.id=d.idDocumentType
WHERE rop.idOrder=$idOrder";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idPackage']][] = $row;
}
$productDocuments = $this->getProductDocuments($idOrder);
if(!empty($productDocuments)){
foreach ($productDocuments as $idPackage => &$documents) {
if(isset($data[$idPackage])){
$data[$idPackage] = array_merge($data[$idPackage], $documents);
}else{
$data[$idPackage] = $documents;
}
}
}
return $data;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,122 @@
<?php
class OrderProcessHelper{
/**
* get all steps for an order
* @param INT $idOrder id of the order
* @return Array list of steps for an order grouped by process and package
*/
public function getOrderSteps($idOrder){
global $database, $user;
$userType = $user->getUserType();
$extraWhereClause = '';
$extraJoin = '';
$comments = $this->getStepComments($idOrder);
if($userType === USER_TYPES['CUSTOMER']) {
$extraWhereClause = " AND ps.isVisibleForCustomer = 1";
}
if($userType === USER_TYPES['SUPPLIER']) {
$extraJoin = " INNER JOIN(
SELECT DISTINCT rop.idOrder, rop.idPackage
FROM ".TABLES['rel_order_packages']." rop
INNER JOIN ".TABLES['rel_package_products']." rpp
ON rpp.idPackage=rop.idPackage and rpp.packageInstance=rpp.packageInstance
INNER JOIN ".TABLES['suppliers_countries_products']." scp
ON scp.idProduct=rpp.idProduct
INNER JOIN ".TABLES['suppliers']." s
ON s.id=scp.idSupplier
WHERE s.idUSer=".$user->getUserId()." AND rop.idOrder=$idOrder
) supplierPkg
ON rops.idOrder=supplierPkg.idOrder AND rops.idPackage=supplierPkg.idPackage";
}
$sql = "SELECT o.id AS idOrder,
ps.shortDesc,
ps.fullDesc,
ps.isVisibleForCustomer,
psa.actionCode,
psa.stepType,
rops.idProcessStep,
rops.status,
DATE_FORMAT(rops.actualDate, '%D %b, %y') as actualDate,
DATE_FORMAT(NOW(), '%D %b %y') as now,
rps.idProcess,
p.name AS processName
FROM ".TABLES['rel_order_process_step']." rops
INNER JOIN ".TABLES['orders']." o
ON o.id=rops.idOrder
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.id=rops.idProcessStep
INNER JOIN ".TABLES['processes']." p
ON p.id=rps.idProcess
INNER JOIN ".TABLES['process_step']." ps
ON ps.id=rps.idStep
INNER JOIN ".TABLES['process_step_actions']." psa
ON psa.id=ps.idActionCode
$extraJoin
WHERE o.id=".$idOrder."
$extraWhereClause
ORDER BY rps.idProcess, rops.idProcessStep DESC
";
$query = $database->query($sql);
$data = [];
while($row = $database->fetchArray($query)){
$idProcess = $row['idProcess'];
$data[$idProcess]['idProcess'] = $row['idProcess'];
$data[$idProcess]['processName'] = $row['processName'];
unset($row['processName']);
$row['comments'] = isset($comments[$row['idProcessStep']]) ? $comments[$row['idProcessStep']] : [];
$row['isNewCommentVisible'] = $row['isVisibleForCustomer'];
$data[$idProcess]['steps'][] = $row;
}
return $data;
}
/**
* get comments from an order
* @param INT $idOrder id of the order
* @return Array list of comments for an order grouped by idPackage and idProcessStep
*/
private function getStepComments($idOrder){
global $database, $user;
$extraFields = '';
$whereSql = '';
$userType = $user->getUserType();
if($userType === USER_TYPES['BROKER']){
$extraFields = ",rsc.isVisible ";
}else{
$whereSql = " AND rsc.isVisible=1";
}
$sql = "SELECT rsc.id, rsc.idProcessStep,
rsc.idPackage,
rsc.comment,
DATE_FORMAT(rsc.addDate, '%D %b, %y') as addDate,
u.username as user
$extraFields
FROM ".TABLES['rel_step_comments']." rsc
INNER JOIN ".TABLES['users']." u
ON u.id=rsc.idUser
WHERE rsc.idOrder=$idOrder
AND rsc.type = 'stepComment'
$whereSql";
$comments = [];
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$idProcessStep = $row['idProcessStep'];
unset($row['idProcessStep']);
$idPackage = $row['idPackage'];
unset( $row['idPackage']);
$comments[$idPackage][$idProcessStep][] = $row;
}
return $comments;
}
}

View File

@@ -0,0 +1,159 @@
<?php
class OrdersController{
private $model;
function __construct(){
$this->model = new OrdersModel();
}
/**
* returns json response for ongoing orders
* @return list orders json
*/
public function getActiveOrders(){
echo json_encode($this->model->getActiveOrders(), JSON_NUMERIC_CHECK);
}
/**
* returns json response for completed orders
* @return list orders json
*/
public function getHistoryOrders(){
echo json_encode($this->model->getHistoryOrders(), JSON_NUMERIC_CHECK);
}
/**
* gets the info for an order
* @return [json] returns order info
*/
public function getOrderInfo() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
echo json_encode($this->model->getOrderInfo($idOrder), JSON_NUMERIC_CHECK);
}
/**
* update comment for an order
* @return json update message
*/
public function addOrderComment() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : null;
echo json_encode($this->model->addOrderComment($idOrder, $comment));
}
/**
* get customer questionnaires documents
* @return json list of documents
*/
public function getOrderDocumentsPerType(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$documentType = isset($_REQUEST['documentType']) ? $_REQUEST['documentType'] : '';
echo json_encode($this->model->getOrderDocumentsPerType($idOrder, $documentType), JSON_NUMERIC_CHECK);
}
/**
* upload againa questionnaire
* @return json upload message
*/
public function reUploadQuestionaire(){
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idDocument = isset($_REQUEST['idDocument']) ? $_REQUEST['idDocument'] : 0;
echo json_encode($this->model->reUploadQuestionaire($idOrder, $idPackage, $idDocument, $file));
}
/**
* returns the comments and the user id based on the comment type
* @return json array with comments
*/
public function getCommentsByType() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
$commentType = isset($_REQUEST['commentType']) ? $_REQUEST['commentType'] : '';
echo json_encode($this->model->getCommentsByType($idOrder, $idPackage, $idProcessStep, $commentType), JSON_NUMERIC_CHECK);
}
/**
* get information for customer acceptance
* @return json object with customer information
*/
public function getCustomerAcceptance(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
echo json_encode($this->model->getCustomerAcceptance($idOrder), JSON_NUMERIC_CHECK);
}
/**
* upload acceptance document
* @return json upload message
*/
public function uploadAcceptanceDocument(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
echo json_encode($this->model->uploadAcceptanceDocument($idOrder, $file));
}
/**
* customer change acceptance status for a package
* @return Array message confirmation
*/
public function acceptDeclineInstallation(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$actionType = isset($_REQUEST['actionType']) ? $_REQUEST['actionType'] : '';
$declineReason = isset($_REQUEST['declineReason']) ? $_REQUEST['declineReason'] : '';
echo json_encode($this->model->acceptDeclineInstallation($idOrder, $actionType, $declineReason));
}
/**
* returns the installation dates proposed/accepted/rejected by users
* @return json array with installation dates
*/
public function getInstallationDates() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->getInstallationDates($idOrder, $idPackage), JSON_NUMERIC_CHECK);
}
public function getAllDataForInstallation() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$stepIds = isset($_REQUEST['stepsNameForInstallation']) ? $_REQUEST['stepsNameForInstallation'] : '[]';
$fileType = isset($_REQUEST['fileType']) ? $_REQUEST['fileType'] : '';
echo json_encode($this->model->getAllDataForInstallation($idOrder, $stepIds, $fileType));
}
/**
* returns a message if the new date for the installation was successfully added
* @return json array with confirmation messages
*/
public function updateInstallationDate() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$installationDate = isset($_REQUEST['installationDate']) ? $_REQUEST['installationDate'] : '';
$status = isset($_REQUEST['status']) ? $_REQUEST['status'] : '';
echo json_encode($this->model->updateInstallationDate($idOrder, $idPackage, $installationDate, $status));
}
/**
* returns a message if the date was removed successfully
* @return json array with confirmation messages
*/
public function removeMyDate() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$installationDate = isset($_REQUEST['installationDate']) ? $_REQUEST['installationDate'] : '';
echo json_encode($this->model->removeMyDate($idOrder, $idPackage, $installationDate));
}
/**
* sends a mail to the support team
* @return json confirmation message
*/
public function sendSupportMail() {
$ordersInfo = isset($_REQUEST['orderInfo']) ? $_REQUEST['orderInfo'] : '[]';
$orderPackages = isset($_REQUEST['orderPackages']) ? $_REQUEST['orderPackages'] : '[]';
$userText = isset($_REQUEST['supportText']) ? $_REQUEST['supportText'] : '';
echo json_encode($this->model->sendSupportMail($ordersInfo, $orderPackages, $userText));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,86 @@
<?php
class PackageDocuments{
private function getProductDocuments($idPackage = 0){
global $database, $user;
$whreSql = "";
$maxInstWhereSql = "";
$data = [];
if($user->getUserType() !== USER_TYPES['BROKER']){
$whreSql = " AND visibleToCustomer=1";
}
if($idPackage !== 0){
$whreSql .= " AND rpp.idPackage=$idPackage";
$maxInstWhereSql = "AND idPackage=$idPackage";
}
$sql = "SELECT
d.id AS idDocument,
d.documentName,
d.documentPath,
d.extension,
dt.type AS documentType,
rpp.idPackage,
rpd.idProduct
FROM ".TABLES['rel_product_documents']." rpd
INNER JOIN ".TABLES['documents']." d
ON d.id=rpd.idDocument
INNER JOIN ".TABLES['document_types']." dt
ON dt.id=d.idDocumentType
INNER JOIN ".TABLES['rel_package_products']." rpp
ON rpp.idProduct=rpd.idProduct
INNER JOIN (
SELECT MAX(packageInstance) as maxInstance
FROM ".TABLES['rel_package_products']."
WHERE 1=1 $maxInstWhereSql
GROUP BY idPackage
) max_inst
ON max_inst.maxInstance=rpp.packageInstance
WHERE 1=1 $whreSql
";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idPackage']][] = $row;
}
return $data;
}
/**
* get package documents
* @param INT $idPackage id for the pacakge
* @return Array list of documents
*/
public function getPackageDocuments($idPackage = 0){
global $database;
$data[$idPackage] = [];
$whereSql = $idPackage !== 0 ? "WHERE rpd.idPackage=$idPackage" : "";
$sql = "SELECT
d.id AS idDocument,
d.documentName,
d.extension,
rpd.idPackage
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['document_types']." dt
ON dt.id=d.idDocumentType
INNER JOIN ".TABLES['rel_package_documents']." rpd
ON rpd.idDocument=d.id
$whereSql ";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idPackage']][] = $row;
}
$productDocuments = $this->getProductDocuments($idPackage);
foreach ($data as $idPackage => &$documents) {
if(isset($productDocuments[$idPackage])){
$documents = array_merge($documents, $productDocuments[$idPackage]);
}
}
return $data;
}
}

View File

@@ -0,0 +1,193 @@
<?php
/**
* Packages manages required data for packages (prices especially)
*/
class Packages {
const PACKAGE_TYPES = [
'ID_STANDARD_TYPE' => 1,
'ID_OPTION_TYPE' => 2,
'ID_ADDITONAL_TYPE' => 3
];
public function generatePackagePayRow($row, $orderType, $customerInfo, $commissionSplit, $totalCost, $interestRateValue){
$prices = new Prices();
$row['idOrderType'] = $orderType;
$margins = $prices->getPriceMargins($commissionSplit, $row, $totalCost);
if($customerInfo['isSameCompanyAsCl'] == 1){
if($row['packagePayPeriod'] > 0){
$row['fixedExtra'] = $row['minimalFixedPrice'];
$row['recurentExtra'] = $prices->getRecurrentPriceMortage($row, $margins['clMargin'], $interestRateValue);
}else{
$row['fixedExtra'] = $row['minimalFixedPrice'] - $margins['clMargin'];
$row['recurentExtra'] = 0;
}
$row['servicesExtra'] = $row['minimalServicesPrice'];
}else{
$row['fixedExtra'] = $row['fixedExtra'] + $row['minimalFixedPrice'];
$row['recurentExtra'] = $row['packagePayPeriod'] > 0
? $row['recurentExtra'] + $prices->getRecurrentPriceMortage($row, 0, $interestRateValue)
: 0;
$row['servicesExtra'] = $row['servicesExtra'] + $row['minimalServicesPrice'];
}
unset($row['minimalFixedPrice']);
unset($row['minimalServicesPrice']);
unset($row['principalAmount']);
$row['isSameCompanyAsCl'] = $customerInfo['isSameCompanyAsCl'];
return $row;
}
/**
* get all prices types for a package by commercial lead
* @param INT $idCommercialLead id for commercial lead
* @param INT $idPackage id for package(in case of additional or optional it represents the parent package)
* @param INT $type id for package type => see self::PACKAGE_TYPES
* @return Array prices array
*/
public function getPricesForPackages($idCommercialLead, $idPackage, $type, $idPaymentType = 0){
global $database, $user;
$data = [];
$whereSql = "";
$extraJoin = "";
$idUser = $user->getUserId();
$prices = new Prices();
$clCustomersInst = new ClCustomers();
$orderTypeInst = new OrderType();
$interestRate = new InterestRate();
$customerInfo = $clCustomersInst->getClCustomerInfo($idCommercialLead);
$orderType = $customerInfo['idOrderType'] ? $customerInfo['idOrderType'] : $orderTypeInst->getCLDefaultOrderType($idCommercialLead);
if($type === self::PACKAGE_TYPES['ID_STANDARD_TYPE']){
$whereSql = "AND plcl.idPackage=$idPackage";
}
if($type === self::PACKAGE_TYPES['ID_OPTION_TYPE']){
$whereSql = "AND pog.idPackage=$idPackage";
$extraJoin = "INNER JOIN ".TABLES['rel_group_options']." rgo
ON rgo.idOptionPackage=plcl.idPackage
INNER JOIN ".TABLES['package_option_groups']." pog
ON pog.id=rgo.idGroup";
}
$productPrices = $prices->getPackageProductPrices($idPackage);
$totalCost = $prices->calculatePackageTotalCost($productPrices);
$commissionSplit = $prices->getCommissionSplit($idPackage);
$interestRateValue = $interestRate->getInterestRate();
$interestRateCustomers = $interestRate->getInterestRateForCustomers();
if($type === self::PACKAGE_TYPES['ID_ADDITONAL_TYPE']){
$whereSql = "AND rap.idPackage=$idPackage";
$extraJoin = " INNER JOIN ".TABLES['rel_additional_packages']." rap
ON rap.idAdditionalPackage=plcl.idPackage";
}
if($idPaymentType){
$whereSql .= " AND plcl.idPaymentType=$idPaymentType";
}
$sql = "SELECT
IF(custom_prices.idCustomer != 0, custom_prices.idCustomer, c.id) AS idCustomer,
plcl.id as idPrice,
plb.idPackage,
plb.idPaymentType,
pt.payType,
pt.packagePayPeriod,
pt.servicesContractPeriod,
pt.periodUnit,
pt.maxContractPeriod,
plcl.fixedExtra,
plcl.recurentExtra,
plcl.servicesExtra,
plb.minimalFixedPrice,
plb.minimalServicesPrice,
plb.principalAmount
FROM ".TABLES['price_list_broker']." plb
INNER JOIN
(SELECT
plcl.idPackage,
plcl.idPaymentType,
plcl.idCommercialLead,
MAX(IFNULL(idCustomer, 0)) AS idCustomer
FROM
".TABLES['price_list_commercial_lead']." plcl
$extraJoin
LEFT OUTER JOIN ".TABLES['customers']." cust
ON cust.id = plcl.idCustomer
WHERE
(cust.idUser = $idUser OR cust.idUser IS NULL)
$whereSql
AND plcl.idCommercialLead=$idCommercialLead
GROUP BY plcl.idPackage , plcl.idPaymentType
) AS custom_prices
ON plb.idPackage = custom_prices.idPackage
AND plb.idPaymentType = custom_prices.idPaymentType
INNER JOIN ".TABLES['price_list_commercial_lead']." plcl
ON plcl.idPackage = custom_prices.idPackage
AND plcl.idPaymentType = custom_prices.idPaymentType
AND plcl.idCommercialLead = custom_prices.idCommercialLead
AND IFNULL(plcl.idCustomer, 0) = custom_prices.idCustomer
AND plcl.visibleToCustomer = 1
INNER JOIN ".TABLES['payment_types']." pt
ON pt.id = plb.idPaymentType
INNER JOIN ".TABLES['customers']." c
ON c.idUser = ".$idUser;
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$interestRateCust = array_key_exists($row['idCustomer'], $interestRateCustomers) ? $interestRateCustomers[$row['idCustomer']] : $interestRateValue['interestRate'];
$row = $this->generatePackagePayRow($row, $orderType, $customerInfo, $commissionSplit, $totalCost, $interestRateCust);
$data[$row['idPackage']][] = $row;
}
return $data;
}
/**
* checks if the customer is from the same company as the commercial lead
* @param Int $idUser id of the user
* @param Int $idCommercialLead id of the commercial lead
* @return Int 1 if they are from the same company
*/
public function checkIfCustomerIsFromCommercialLeadCompany($idCommercialLead, $isForCart = false) {
global $database, $user;
$extraJoin = "";
$joinClause = "";
$whereClause = "";
$idUser = $user->getUserId();
if($user->getUserType() !== USER_TYPES['CUSTOMER']) {
return;
}
if($isForCart) {
$extraJoin = "INNER JOIN ".TABLES['web_shop_cart']." cart
ON cart.idUser = $idUser
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id = cart.idCustomerInstance";
$joinClause = "AND cl.id = rclc.idCommercialLead";
} else {
$whereClause = "WHERE cl.id = $idCommercialLead";
}
$sql = "SELECT
u.idCompany
FROM
".TABLES['users']." u
$extraJoin
INNER JOIN ".TABLES['commercial_leads']." cl
ON u.id = cl.idUser
$joinClause
INNER JOIN
(SELECT
us.idCompany
FROM
".TABLES['users']." us
WHERE us.id = $idUser) userCompany
ON userCompany.idCompany = u.idCompany
$whereClause";
$result = $database->query($sql);
return $database->numRows($result) > 0;
}
}

View File

@@ -0,0 +1,323 @@
<?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, '.', '');
}
}

View File

@@ -0,0 +1,85 @@
<?php
/**
* Profile Settings controlls the actions for the shop
*/
class ProfileSettingsController{
private $model;
function __construct(){
$this->model = new ProfileSettingsModel();
}
/**
* get info for a user profile
* @return [type] json containg profile info
*/
public function getProfileInfo(){
$idUser = isset($_REQUEST['idUser']) ? $_REQUEST['idUser'] : '';
$json = json_encode($this->model->getProfileInfo($idUser), JSON_NUMERIC_CHECK);
echo preg_replace('/'.STRING_START.'/', '', $json);
}
/**
* save info for profile
* @return [type] json containg update message
*/
public function saveProfileInfo(){
$idUser = isset($_REQUEST['idUser']) ? $_REQUEST['idUser'] : '';
$profile = isset($_REQUEST['profile']) ? $_REQUEST['profile'] : '[]';
echo json_encode($this->model->saveProfileInfo($idUser, $profile), JSON_NUMERIC_CHECK);
}
/**
* save company information
* @return [type] json containing update message
*/
public function saveCompanyInfo(){
$companyInfo = isset($_REQUEST['companyInfo']) ? $_REQUEST['companyInfo'] : '[]';
echo json_encode($this->model->saveCompanyInfo($companyInfo), JSON_NUMERIC_CHECK);
}
/**
* remove delivery address
* @return json update message
*/
public function removeProfileAddress(){
$idProfileAddress = isset($_REQUEST['idProfileAddress']) ? $_REQUEST['idProfileAddress'] : 0;
echo json_encode($this->model->removeProfileAddress($idProfileAddress), JSON_NUMERIC_CHECK);
}
/**
* save delivery address
* @return json update message
*/
public function saveProfileAddress(){
$profileAddress = isset($_REQUEST['profileAddress']) ? $_REQUEST['profileAddress'] : '[]';
echo json_encode($this->model->saveProfileAddress($profileAddress), JSON_NUMERIC_CHECK);
}
/**
* remove billing address
* @return json update message
*/
public function removeBillingAddress(){
$idBillingAddress = isset($_REQUEST['idBillingAddress']) ? $_REQUEST['idBillingAddress'] : 0;
echo json_encode($this->model->removeBillingAddress($idBillingAddress), JSON_NUMERIC_CHECK);
}
/**
* save billing address
* @return json update message
*/
public function saveBillingAddress(){
$idCompany = isset($_REQUEST['idCompany']) ? $_REQUEST['idCompany'] : 0;
$billingAddress = isset($_REQUEST['billingAddress']) ? $_REQUEST['billingAddress'] : '[]';
echo json_encode($this->model->saveBillingAddress($idCompany, $billingAddress), JSON_NUMERIC_CHECK);
}
/**
* get countries array
* @return json countires array
*/
public function getCoutnries(){
echo json_encode($this->model->getCoutnries(), JSON_NUMERIC_CHECK);
}
}

View File

@@ -0,0 +1,238 @@
<?php
/**
* Data manipulation for the model
*/
class ProfileSettingsModel{
private function getUserTypeById($idUser){
global $database;
$sql = "SELECT ut.type
FROM ".TABLES['user_types']." ut
INNER JOIN ".TABLES['rel_user_type']." rut
ON rut.idType=ut.id
WHERE rut.idUser=$idUser";
$query = $database->query($sql);
$row = $database->fetchArray($query);
return $row['type'];
}
/**
* get profile info
* @param INT $idUser id user //broker can see data for all users
* @return HashArray user profile information including company information
*/
public function getProfileInfo($idUser){
global $database, $user;
$userType = $user->getUserType();
$targetUserType = ($userType === USER_TYPES['BROKER'] && $idUser != 0 ) ? $this->getUserTypeById($idUser) : $userType;
$idUser = $database->escapeValue($idUser);
if( intval($idUser) === 0){
$idUser = $user->getUserId();
}
$addresHelper = new AddressHelper();
$sql = "SELECT ui.id,
ui.name,
ui.phone,
u.mail,
u.isCompanyAdmin,
u.idCompany,
ut.idType AS idUserType,
c.name AS companyName,
c.vatCode
FROM ".$user->getTableByUser($targetUserType)." ui
INNER JOIN ".TABLES['users']." u
ON u.id=ui.idUser
INNER JOIN ".TABLES['rel_user_type']." ut
ON ut.idUser=u.id
LEFT OUTER JOIN ".TABLES['company']." c
ON u.idCompany=c.id
WHERE u.id=$idUser
";
$query = $database->query($sql);
$row = $database->fetchArray($query);
if($row){
$row['phone'] = STRING_START.$row['phone'];
if($userType === USER_TYPES['CUSTOMER']){
$row['profileAddresses'] = $addresHelper->getDeliveryAddress();
$row['billingAddresses'] = $addresHelper->getBillingAddress();
}
$row['userType'] = $userType;
}
return $row;
}
/**
* save profile information
* @param INT $idUser id user
* @param Object $profile profile information to save
* @return Array save messages
*/
public function saveProfileInfo($idUser, $profile){
global $database, $user;
$profile = json_decode($profile);
$userHelper = new UsersHelper();
$userType = $user->getUserType();
$targetUserType = ($userType === USER_TYPES['BROKER'] && $idUser != 0 ) ? $this->getUserTypeById($idUser) : $userType;
$idUser = $database->escapeValue($idUser);
if( intval($idUser) === 0){
$idUser = $user->getUserId();
}
$data = [];
if(!$idUser || !$userHelper->checkRightsToEdit($idUser)) {
$err_mes = [
'code' => 'error',
'message' => 'INVALID_USER'
];
$data['messages'][] = $err_mes;
return $data;
}
if(!$profile){
$err_mes = [
'code' => 'error',
'message' => 'INVALID_PROFILE_DATA'
];
$data['messages'][] = $err_mes;
return $data;
}
$checkMessage = $userHelper->validateUserData('edit', $profile);
if(!empty($checkMessage)){
return $checkMessage;
}
$sql = "UPDATE ".$user->getTableByUser($targetUserType)."
SET name='".$profile->name."',
phone='".$profile->phone."'
WHERE id=".$profile->id;
$query = $database->query($sql);
if($database->affectedRows()) {
$mes = [
'code' => 'success',
'message' => 'PROFILE_UPDATED'
];
}else{
$mes = [
'code' => 'warning',
'message' => 'PROFILE_NOT_CHANGED'
];
}
$data['messages'][] = $mes;
return $data;
}
/**
* save company information
* @param Object $companyInfo copmany information
* @return Arary save messages
*/
public function saveCompanyInfo($companyInfo){
global $database, $user;
$companyInfo = json_decode($companyInfo);
$userHelper = new UsersHelper();
$data = [];
if(!$userHelper->checkRightsToEditCompany($companyInfo->idCompany)){
$err_mes = [
'code' => 'error',
'message' => 'NOT_COMPANY_ADMIN'
];
$data['messages'][] = $err_mes;
return $data;
}
$checkMessage = $userHelper->validateCompanyData($companyInfo);
if(!empty($checkMessage)){
return $checkMessage;
}
$sql = "UPDATE ".TABLES['company']."
SET name='".$companyInfo->companyName."',
vatCode='".$companyInfo->vatCode."'
WHERE id=".$companyInfo->idCompany;
$query = $database->query($sql);
if($database->affectedRows()) {
$mes = [
'code' => 'success',
'message' => 'COMPANY_UPDATED'
];
}else{
$mes = [
'code' => 'warning',
'message' => 'COMPANY_NOT_CHANGED'
];
}
$data['messages'][] = $mes;
return $data;
}
/**
* remove delivery address
* @param INT $idProfileAddress id delivery address
* @return Array update message
*/
public function removeProfileAddress($idProfileAddress){
$addresHelper = new AddressHelper();
return $addresHelper->removeProfileAddress($idProfileAddress);
}
/**
* save delivery address
* @param Object $profileAddress delivery address information
* @return Array update message
*/
public function saveProfileAddress($profileAddress){
$addresHelper = new AddressHelper();
return $addresHelper->saveProfileAddress($profileAddress);
}
/**
* remove billing address
* @param INT $idBillingAddress billing address information
* @return Array update message
*/
public function removeBillingAddress($idBillingAddress){
$addresHelper = new AddressHelper();
return $addresHelper->removeBillingAddress($idBillingAddress);
}
/**
* save billing address
* @param INT $idCompany id for company
* @param Object $billingAddress billing address information\
* @return Array update message
*/
public function saveBillingAddress($idCompany, $billingAddress){
$addresHelper = new AddressHelper();
return $addresHelper->saveBillingAddress($idCompany, $billingAddress);
}
/**
* get countires
* @return Array list of countries
*/
public function getCoutnries(){
$countries= new Countries();
return $countries->getCountries();
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* TermsController controlls the actions for the terms and conditions page
*/
class TermsController{
private $model;
function __construct(){
$this->model = new TermsModel();
}
/**
* output file content for pdf verison of terms and conditions
* @return file pdf file content
*/
public function pdfTerms(){
header("Content-type: application/pdf");
header("Content-Disposition: inline; filename=\"".APPLICATION_NAME." Terms and Conditions.pdf\"");
$idTerms = isset($_REQUEST['idTerms']) ? $_REQUEST['idTerms'] : 0;
echo $this->model->pdfTerms($idTerms);
}
/**
* open shop page
*/
public function getTerms(){
$idTerms = isset($_REQUEST['idTerms']) ? $_REQUEST['idTerms'] : 0;
echo json_encode($this->model->getTermsHTML($idTerms));
}
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Data manipulation for the terms
*/
class TermsModel{
/**
* get html version form terms and conditions
* @return string html string for terms and conditions
*/
public function getTermsHTML($idTerms){
global $database;
$extraSql = intval($idTerms) === 0 ? "ORDER BY id DESC" : "WHERE id=$idTerms";
$sql = "SELECT html, version
FROM ".TABLES['terms']."
$extraSql
LIMIT 1";
$row = $database->fetchResultArray($sql);
return !empty($row) ? $row[0] : [];
}
/**
* get pdf version for terms and conditions
* @return bloob hex for pdf file
*/
public function pdfTerms($idTerms){
global $database;
$extraSql = intval($idTerms) === 0 ? "ORDER BY id DESC" : "WHERE id=$idTerms";
$sql = "SELECT pdf
FROM ".TABLES['terms']."
$extraSql
LIMIT 1";
$pdf = $database->fetchResultArray($sql);
return !empty($pdf) ? $pdf[0]['pdf'] : 'invalid pdf';
}
}

View File

@@ -0,0 +1,197 @@
<?php
class UsersHelper {
public function checkRightsToEdit($idUser) {
global $database, $user;
$userType = $user->getUserType($idUser);
if($userType === USER_TYPES['BROKER']){
return true;
}
return $idUser === $user->getUserId();
}
public function checkRightsToEditCompany($idCompany) {
global $database, $user;
$sql = "SELECT u.isCompanyAdmin
FROM ".TABLES['users']." u
WHERE u.id=".$user->getUserId()." AND u.idCompany=".$idCompany;
$query = $database->query($sql);
$row = $database->fetchArray($query);
return $row ? $row['isCompanyAdmin'] === '1' : $user->getUserType() === USER_TYPES['BROKER'];
}
/**
* validate user data from GUI
* @param Array $info all information about the company to be inserted/updated
* @return Array empty or error message
*/
public function validateCompanyData($info){
global $database;
$data = [];
foreach (get_object_vars($info) as $key => $value) {
$info->{$key} = $database->escapeValue($value);
}
if(!isset($info->idCompany) || empty($info->idCompany)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_COMPANY'
];
return $data;
}
if(!isset($info->vatCode) || empty($info->vatCode)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_VAT'
];
return $data;
}
$checkMessage = $database->invalidLength('vatCode', $info->vatCode, 20);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if(!isset($info->companyName) || empty($info->companyName)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_COPMANY_NAME'
];
return $data;
}
$checkMessage = $database->invalidLength('companyName', $info->companyName, 100);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
return $data;
}
/**
* validate user data from GUI
* @param String $action add or edit action
* @param Array $info all information about the user to be inserted/updated
* @param Array $commercialLeads all the commercial leads linked to a customer
* @return Array empty or error message
*/
public function validateUserData($action, $info, $commercialLeads = []) {
global $database;
$data = [];
foreach (get_object_vars($info) as $key => $value) {
$info->{$key} = $database->escapeValue($value);
}
if(!$info->idUserType) {
$data['messages'][] = [
'code' => 'error',
'message' => 'SELECT_USER_TYPE'
];
return $data;
}
if(!isset($info->name) || empty($info->name)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_NAME'
];
return $data;
}
$checkMessage = $database->invalidLength('name', $info->name, 200);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if(!isset($info->phone) || empty($info->phone)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_PHONE_NUMBER'
];
return $data;
}
if(!preg_match('/^([0-9\(\)\/\+ \-]*)$/', $info->phone)){
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_PHONE_NUMBER'
];
}
$checkMessage = $database->invalidLength('phone', $info->phone, 40);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if($action === 'add'){
if($info->idUserType === '2' && empty($commercialLeads)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_COMMERCIAL_LEAD_LINK'
];
return $data;
}
if(!isset($info->username) || empty($info->username)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_USERNAME'
];
return $data;
}
$checkMessage = $database->invalidLength('username', $info->username, 20);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if(!preg_match('/^[a-zA-Z\d\.\-_]+$/',$info->username)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_USERNAME'
];
}
$sql = "SELECT username
FROM ".TABLES['users']."
WHERE username='".$info->username."'
LIMIT 1";
$result = $database->query($sql);
if($database->numRows($result) > 0) {
$data['messages'][] = [
'code' => 'error',
'message' => 'USERNAME_EXISTS'
];
}
if(!isset($info->mail) || empty($info->mail)) {
$data['messages'][] = [
'code' => 'error',
'message' => 'ADD_MAIL'
];
return $data;
}
if(!filter_var($info->mail, FILTER_VALIDATE_EMAIL)){
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_MAIL'
];
}
}
return $data;
}
}

View File

@@ -0,0 +1,15 @@
<?php
class UtilsController{
private $model;
function __construct(){
$this->model = new UtilsModel();
}
public function downloadFile(){
$fileName = isset($_REQUEST['fileName']) ? $_REQUEST['fileName'] : '';
$idDocument = isset($_REQUEST['idDocument']) ? $_REQUEST['idDocument'] : 0;
$fileType = isset($_REQUEST['fileType']) ? $_REQUEST['fileType'] : '';
echo $this->model->downloadFile($idDocument, $fileName, $fileType);
}
}

View File

@@ -0,0 +1,426 @@
<?php
class UtilsModel{
const ID_TYPE_CUSTOMER = 2;
public function downloadFile($idDocument, $fileName, $fileType){
$fileManager = new FileManager();
return $fileManager->downloadFile($idDocument, $fileName, $fileType);
}
public static function sendOrderUpdateMail($mailType, $params, $mailTitle, $mails) {
global $user;
$templateUrl = $mailType.'Template.php';
if(array_key_exists('customer', $mails) && count($mails['customer'])) {
$response = Mail::sendMail($mails['customer'], $mailTitle, $templateUrl, $params);
}
if($user->getUserType() !== USER_TYPES['BROKER']) {
$usersMails = array_key_exists('other', $mails) ? (array) $mails['other'] : [];
$brokerMails = (array) self::getBrokersMail();
$mails['other'] = array_merge($usersMails, $brokerMails);
$params['orderUrl'] = $params['apiOrderUrl'];
$response = Mail::sendMail($mails['other'], $mailTitle, $templateUrl, $params);
}
if($response){
return [
'code' => 'success',
'message' => 'ORDER_UPDATE_MAIL_SENT'
];
}
return [
'code' => 'error',
'message' => 'ERROR_MAIL_SENT'
];
}
/**
* send order confirmation email to user
* @param Array $cartPackages contains the packages ordered
* @param String $userType customer or broker
* @param Array $orderInfo contains information about the order like id, order number and so on
* @return Array confirmation message
*/
public static function sendOrderConfirmationMail($cartPackages, $userType, $orderInfo) {
$mail = '';
$orderUrl = WIAAS_URL.'/api-wiaas/orders?subModule=orders_steps&idOrder='.$orderInfo['idOrder'].'&orderNumber='.$orderInfo['orderNumber'];
if($userType === USER_TYPES['CUSTOMER']) {
$templateUrl = 'orderConfirmationTemplate.php';
$mailTitle = 'Order successfully placed';
$userData = self::getUserData();
if($userData && $userData[0]['mail']) {
$mail = $userData[0]['mail'];
}
$message = 'MAIL_SENT';
$orderUrl = WIAAS_URL.'/orders/'.$orderInfo['idOrder'];
} else if($userType === USER_TYPES['BROKER']){
$templateUrl = 'orderConfirmationBrokerTemplate.php';
$mailTitle = 'New order placed';
$brokerData = self::getBrokersMail();
if($brokerData) {
$mail = $brokerData;
}
$message = 'BROKER_MAIL_SENT';
}
$currentDate = new DateTime();
$currentDate = $currentDate->format('d-m-Y H:i');
$params = [
'cartPackages' => $cartPackages,
'currentDate' => $currentDate,
'orderNumber' => $orderInfo['orderNumber'],
'orderDate' => $orderInfo['orderDate'],
'orderUrl' => $orderUrl
];
$response = Mail::sendMail($mail, $mailTitle, $templateUrl, $params);
if($response){
return [
'code' => 'success',
'message' => $message
];
}
return [
'code' => 'error',
'message' => 'ERROR_MAIL_SENT'
];
}
/**
* fetches the username and the email for the broker
* @return String mail of the broker
*/
public static function getBrokersMail() {
global $database;
$sql="
SELECT u.mail
FROM ".TABLES['brokers']." b
INNER JOIN ".TABLES['users']." u
ON u.id = b.idUser";
$result = $database->query($sql);
while($row = $database->fetchArray($result)) {
if($row['mail'] !== '') {
$mailArray[] = $row['mail'];
}
}
return (count($mailArray) === 0 || count($mailArray) > 1) ? $mailArray : $mailArray[0];
}
/**
* fetches the username and the email for the user logged in
* @return Array username and mail
*/
private static function getUserData($username = '') {
global $database, $user;
$username = $username ? $username : $user->getUser();
$sql = "SELECT
u.mail,
u.username,
ut.type,
rut.idType AS idUserType
FROM ".TABLES['users']." u
INNER JOIN ".TABLES['rel_user_type']." rut
ON rut.idUser=u.id
INNER JOIN ".TABLES['user_types']." ut
ON ut.id = rut.idType
WHERE u.username='".$database->escapeValue($username)."'";
return $database->fetchResultArray($sql);
}
/**
* generate a filter condition on gadget filter
* @param Array $filters array of filters
* @return string sql filter condtion
*/
public static function setFilterSql($filters){
$whereSql = "1=1";
if(!empty($filters)){
foreach ($filters as $key => $filterValue) {
$whereSql .= " AND $key like '%$filterValue%'";
}
}
return $whereSql;
}
/**
* add sorting for orders central
* @param String $sortBy sql for order by
*/
public static function setOrderBySql($sortBy){
$orderBySql = "";
if(isset($sortBy->key) && isset($sortBy->direction) ){
$orderBySql .= $sortBy->key." ".$sortBy->direction;
}
return $orderBySql;
}
/**
* changes the password for the current user
* @param String $password if empty, a random pass will be generated
* @return Array confirmation message
*/
public static function changePassword($passwords, $username = '') {
global $database, $user;
$passwords = (array) json_decode($passwords);
if($userInfo = self::getUserData($username)) {
$userInfo = $userInfo[0];
} else {
$data['messages'][] = [
'code' => 'error',
'message' => 'WRONG_USERNAME'
];
return $data;
}
$isForReset = $username ? true : false;
if($data = self::validatePassword($userInfo['username'], $passwords, $isForReset)) {
return $data;
}
$password = $passwords['newPassword'];
$passwordHashed = $user->hashPassword($database->escapeValue($password));
$sql = "UPDATE
".TABLES['users']." u
SET
u.password='".$passwordHashed."',
u.token=null,
u.tokenTS=null
WHERE u.username='".$database->escapeValue($userInfo['username'])."'";
$result = $database->query($sql);
if($database->affectedRows() == 1) {
$data['messages'][] = [
'code' => 'success',
'message' => 'PASSWORD_GENERATED'
];
} else {
$data['messages'][] = [
'code' => 'error',
'message' => 'ERROR_PASSWORD_GENERATED'
];
}
$data['messages'][] = self::sendUserConfirmationMail($userInfo, $userInfo['mail'], 'change');
return $data;
}
private static function validatePassword($username, $passwordData, $isForReset = false) {
global $database, $user;
$data = [];
if ((!array_key_exists('newPassword', $passwordData) || $passwordData['newPassword'] === '') ||
(!array_key_exists('confirmPassword', $passwordData) || $passwordData['confirmPassword'] === '')) {
$data['messages'][] = [
'code' => 'error',
'message' => 'PASSWORDS_MISSING'
];
return $data;
}
$newPassword = $database->escapeValue($passwordData['newPassword']);
$confirmPassword = $database->escapeValue($passwordData['confirmPassword']);
if(!$isForReset) {
if($data = self::validateOldPassword($passwordData, $username)) {
return $data;
}
$oldPassword = $database->escapeValue($passwordData['oldPassword']);
if($oldPassword === $newPassword) {
$data['messages'][] = [
'code' => 'error',
'message' => 'PASSWORD_SAME'
];
return $data;
}
}
if($newPassword !== $confirmPassword) {
$data['messages'][] = [
'code' => 'error',
'message' => 'PASSWORD_MISMATCH'
];
return $data;
}
if((strlen($newPassword) < 8) ||
!preg_match("/((?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%-_]).{8,20})/", $newPassword)
) {
$data['messages'][] = [
'code' => 'error',
'message' => 'PASSWORD_INCORRECT'
];
}
return $data;
}
private static function validateOldPassword($passwordData, $username) {
global $database, $user;
$data = [];
$oldPassword = $database->escapeValue($passwordData['oldPassword']);
if (!array_key_exists('oldPassword', $passwordData) || $passwordData['oldPassword'] === '') {
$data['messages'][] = [
'code' => 'error',
'message' => 'PASSWORDS_MISSING'
];
return $data;
}
$sql = "SELECT u.password
FROM ".TABLES['users']." u
WHERE u.username='".$database->escapeValue($username)."'
LIMIT 1";
$row = $database->fetchResultArray($sql);
if($row[0] && $row[0]['password'] && !password_verify($oldPassword, $row[0]['password'])) {
$data['messages'][] = [
'code' => 'error',
'message' => 'OLD_PASSWORD_MISMATCH'
];
}
return $data;
}
/**
* send confirmation mail to user for creation
* @param Object $userInfo
* @param String $password
* @param String $mail
* @return Array confirmation message
*/
public static function sendUserConfirmationMail($userInfo, $mail, $action, $token = '') {
switch($action) {
case 'create':
$mailTitle = APPLICATION_NAME.' user created';
$templateUrl = 'createUserTemplate.php';
break;
case 'generate':
$mailTitle = APPLICATION_NAME.' password generated';
$templateUrl = 'generatePasswordUserTemplate.php';
break;
case 'change':
$mailTitle = APPLICATION_NAME.' password changed';
$templateUrl = 'changedPasswordTemplate.php';
break;
default:
return [
'code' => 'error',
'message' => 'ACTION_NOT_SET'
];
}
$passwordValidationUrl = $userInfo['idUserType'] == self::ID_TYPE_CUSTOMER ? WIAAS_URL.'/changePassword/' . $token : WIAAS_URL.'/api-wiaas/login?token=' . $token;
$params = [
'username' => $userInfo['username'],
'wiaas' => $userInfo['type'] === USER_TYPES['CUSTOMER'] ? WIAAS_URL : WIAAS_URL.'/api-wiaas',
'urlValidate' => $passwordValidationUrl
];
$response = Mail::sendMail($mail, $mailTitle, $templateUrl, $params);
if($response){
return [
'code' => 'success',
'message' => 'MAIL_SENT'
];
}
return [
'code' => 'error',
'message' => 'ERROR_MAIL_SENT'
];
}
/**
* return true or false if the user logged in is a company admin or not
* @return Bool true if the user is company admin
*/
public static function checkIfUserIsCompanyAdmin() {
global $database, $user;
$idUser = $user->getUserId();
$sql = "
SELECT
u.isCompanyAdmin
FROM
".TABLES['users']." u
WHERE u.id = $idUser";
$data = $database->fetchResultArray($sql);
return count($data) && $data[0]['isCompanyAdmin'] ? true : false;
}
/**
* returns the mail and order number for an order
* @param Int $idOrder the id of the order
* @return Array mail of the customer and the order number
*/
public static function getDataForMailToCustomer($idOrder) {
global $database;
$sqlCustomerInfo = "
SELECT u.mail,
o.orderNumber
FROM ".TABLES['customers']." c
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON c.id=rclc.idCustomer
INNER JOIN ".TABLES['users']." u
ON u.id = c.idUser
INNER JOIN ".TABLES['orders']." o
ON o.idCustomerInstance=rclc.id
WHERE o.id=$idOrder
LIMIT 1";
$query = $database->query($sqlCustomerInfo);
return $database->fetchArray($query);
}
/**
* get the orderNumber based on the order id
* @param Int $idOrder the id of the order
* @return Int the order number of that order
*/
public static function getOrderNumberById($idOrder) {
global $database;
$sql = "
SELECT
o.orderNumber
FROM
".TABLES['orders']." o
WHERE o.id = $idOrder
LIMIT 1
";
$orderNumberArray = $database->fetchResultArray($sql);
if($orderNumberArray && $orderNumberArray[0]) {
return array_key_exists('orderNumber', $orderNumberArray[0]) ? $orderNumberArray[0]['orderNumber'] : '';
}
return '';
}
}

View File

@@ -0,0 +1,18 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
Welcome back to {APPLICATION_NAME}!<br/>
The password was changed successfully for <b>{username}</b>!<br /><br />
Please use this link to login: <a href="{wiaas}">{wiaas}</a>.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,20 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
Welcome to {APPLICATION_NAME}!<br/>
Click on <a href="{urlValidate}">this link</a> to set your password.<br />
This link will expire after 5 days.<br /><br />
Please use this link to login: <a href="{wiaas}">{wiaas}</a>, after setting your password.<br/>
Your username is: <b>{username}</b><br/>
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,26 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
Welcome back to {APPLICATION_NAME}!<br/>
The schedule installation function for order {orderNumber} for package {packageName} is now active.<br /><br />
To propose a date for the installation, go to <a href="{ordersUrl}">this</a> link and click on <b>Schedule installation</b> button on the order details header. <br />
There are displayed the earliest installation date (this is the date when all the products can be shipped in order to perform the installation), <br />
the company which will perform the installation and the already proposed dates. <br />
To propose a date, click on the <b>Add optional date</b> button and select a date which suites you to perform the installation.<br />
Also the installation company user, <b>{supplierName}</b>, will propose a date/dates for its convenience.<br /><br />
After you propose a date, the installation company is notified, and he will accept or decline that date.<br />
And reversed, if there is already a date proposed, you can accept or decline it.<br /><br />
Please note that there cannot be two dates accepted at the same time. If there is already an accepted date, and you accept another one, the first date accepted will be canceled and the last one will remain accepted.<br /><br />
You can access the application <a href="{wiaas}">here</a>.<br />
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,11 @@
<html>
<head>
<title></title>
</head>
<body>
{errorMessage}
</body>
</html>

View File

@@ -0,0 +1,20 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
Welcome back to {APPLICATION_NAME}!<br/>
You have requested a new password<br />
Click on <a href="{urlValidate}">this link</a> to reset your password.
<br/>
Your username is: <b>{username}</b><br/>
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,17 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
Installation date <b>{acceptedDate}</b> for order {orderNumber} was accepted by {actionDoneBy}.<br/>
You can go to <a href="{ordersUrl}">{APPLICATION_NAME}</a> to view more details.<br />
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,17 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
The installation date accepted by both parties, {acceptedDate}, for order {orderNumber}, was marked invalid due to the confirmed shipping dates.<br />
You can go to <a href="{ordersUrl}">{APPLICATION_NAME}</a> to propose new dates for the installation.<br />
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,17 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
All the proposed installation dates for order {orderNumber} were declined.<br/>
You can go to <a href="{ordersUrl}">{APPLICATION_NAME}</a> to propose new dates for the installation.<br />
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,17 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
{actionDoneBy} proposed a new installation date: <b>{proposedDate}</b> for order {orderNumber}.<br />
Go to <a href="{ordersUrl}">{APPLICATION_NAME}</a> to plan the installation.<br />
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,18 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
The schedule installation function for order {orderNumber} is now disabled.<br /><br />
You will receive an email notification when this function will be re-actived.<br />
Go to <a href="{ordersUrl}">this</a> link to see the status of your order. <br />
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,19 @@
<html>
<head>
<title></title>
</head>
<body>
Hello,<br/></br/>
The questionnaire you have uploaded for the order {orderNumber} need to be modified! Please see the comments on order.<br/>
Reason:<br />
{invalidQuestionaireReason}<br /><br />
You can download the file using this <a href="{url}">link</a> and upload it again using this <a href="{ordersUrl}">link</a>.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,22 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/>
<br/>
The order <b>{orderNumber}</b> has been updated in {currentDate}.<br/>
{prevStepMessage}
The delivery is now completed for the package: <b>{packageName}</b>.
<br />
<br />
Access {APPLICATION_NAME} <a href="{orderUrl}">here</a> to see more details.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,21 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/>
<br/>
A new comment has been added by <b>{userLoggedIn}</b> for order {orderNumber} at {currentDate}:<br />
<br />
<b>{commentMessage}</b><br />
<br />
You can access the order <a href="{orderUrl}">here</a> to see more details.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,17 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
An order has been placed successfully in {currentDate}.<br/>
Please go to <a href="{orderUrl}">{APPLICATION_NAME}</a> to link a process to that package(s) from the order.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,20 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
Your order has been successfully submitted: {currentDate}.<br/>
The order <b>{orderNumber}</b>, date: {orderDate} includes the following order rows:<br />
{cartPackages}
<br />
Access {APPLICATION_NAME} <a href="{orderUrl}">here</a> to see the progress of your order.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,20 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/>
<br/>
Your order <b>{orderNumber}</b> has been set to: {status} in {currentDate}.<br />
{deliveryEstimationDateMessage}
<br />
You can access {APPLICATION_NAME} <a href="{orderUrl}">here</a> to see more details.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,21 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
The order {orderNumber} has been updated {currentDate}.<br/>
<br />
{prevStepMessage}
{currentStepMessage}
<br />
Access {APPLICATION_NAME} <a href="{orderUrl}">here</a> to check the progress of the order.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,20 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/>
<br/>
The order row "{packageName}", of order <b>{orderNumber}</b>, has been changed to: {status} in {currentDate}.<br />
{deliveryEstimationDateMessage}
<br />
You can access {APPLICATION_NAME} <a href="{orderUrl}">here</a> to see more details.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,19 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
We have now started processing the order <b>{orderNumber}</b> ({currentDate}).<br/>
<br />
<br />
Access {APPLICATION_NAME} <a href="{orderUrl}">here</a> to check the progress of the order.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,16 @@
<html>
<head>
<title></title>
</head>
<body>
Hello,<br/></br/>
A new questionaire has been uploaded for the order <a href="{ordersUrl}">{orderNumber}</a> and needs validation!
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>

View File

@@ -0,0 +1,21 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/>
<br/>
The order's <b>{orderNumber}</b> follow-up meeting date has changed in {currentDate}.<br />
{estimatedDateMessage}
{confirmedDateMessage}
<br />
You can access {APPLICATION_NAME} <a href="{orderUrl}">here</a> to see more details.
<br/>
<br/>
Best regards,<br/>
{APPLICATION_NAME} team
</body>
</html>

View File

@@ -0,0 +1,59 @@
<html>
<head>
<title></title>
</head>
<body>
Hello, <br/><br/>
{customerName} has sent an email for support for order {orderNumber}.<br/>
<br />
<h4>Customer details</h4>
<div class="row">
<span class="col-md-3">Name:</span>
<span class="col-md-3">{customerName}</span>
</div>
<div class="row">
<span class="col-md-3">Mail:</span>
<span class="col-md-3">{customerMail}</span>
</div>
<div class="row">
<span class="col-md-3">Phone:</span>
<span class="col-md-3">{customerPhone}</span>
</div>
<br/>
<hr />
<h4>Order details</h4>
<div class="order-informations col-md-12">
<div>
<span class="order-number-icon">#</span>
<b>Order number:</b> {orderNumber}
</div>
<div>
<span class="glyphicon glyphicon-link"></span>
<b>Reference: </b>{reference}
</div>
<div>
<span class="glyphicon glyphicon-dashboard"></span>
<b>Tender: </b>{tender}
</div>
<div>
<span class="glyphicon glyphicon-user"></span>
<b>Commercial lead: </b>{commercialLead}
</div>
<hr />
</div>
<div class="packages-info col-md-12">
<h4>Order Items</h4>
{orderItems}
</div>
<hr />
<h4>Customer's comment</h4>
{userText}
<hr />
<br/>
Best regards,<br/>
{APPLICATION_NAME} administrators
</body>
</html>