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,52 @@
<?php
class BidMargin{
public function addBidMargin($idBid, $bidMargin){
global $database;
$data = [];
$bidMargin = json_decode($bidMargin);
if($idBid === 0){
$data['messages'][] =[
'code' => 'error',
'message' => 'BID_ID_REQUIRED'
];
return $data;
}
if(!property_exists($bidMargin, 'fixedExtra')
|| !property_exists($bidMargin, 'recurrentExtra')
|| !property_exists($bidMargin, 'servicesExtra')){
$data['messages'][] =[
'code' => 'error',
'message' => 'BID_MARGINS_REQUIRED'
];
return $data;
}
$sql = "UPDATE ".TABLES['packages_bids']."
SET fixedExtra=".$database->escapeValue($bidMargin->fixedExtra).",
recurrentExtra=".$database->escapeValue($bidMargin->recurrentExtra).",
servicesExtra=".$database->escapeValue($bidMargin->servicesExtra)."
WHERE id=".$database->escapeValue($idBid);
$query = $database->query($sql);
if($database->affectedRows() === 0){
$data['messages'][] =[
'code' => 'error',
'message' => 'SERVER_ERROR'
];
return $data;
}
$data['messages'][] = [
'code' => 'success',
'message' => 'BID_MARGIN_ADDED'
];
return $data;
}
}

View File

@@ -0,0 +1,231 @@
<?php
class Bids {
public function getBids($filter){
global $database, $user;
$data = [];
$bids = [];
$pricesHandler = new Prices();
$interestRate = new InterestRate();
$supplierBidsHandler = new SupplierBids();
$interestRateValue = $interestRate->getInterestRate()['interestRate'];
$interestRateCustomers = $interestRate->getInterestRateForCustomers();
$supplierBids = $supplierBidsHandler->getLinkedSupplierBids();
$clSql = "";
if($user->getUserType() === USER_TYPES['COMMERCIAL_LEAD']){
$clSql = " AND cl.idUser=".$user->getUserId();
}
$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,
pb.startDate,
pb.endDate,
pb.fixedPrice,
pb.principalAmount,
pb.servicesPrice,
CASE WHEN pb.endDate >= NOW() THEN 'available' ELSE 'expired' END AS status,
CASE WHEN rop.idBid IS NULL THEN 0 ELSE 1 END AS isUsed
FROM ".TABLES['packages_bids']." pb
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
LEFT OUTER JOIN (
SELECT DISTINCT idBid
FROM ".TABLES['rel_order_packages']."
) rop
ON rop.idBid=pb.id
WHERE 1=1 $clSql
ORDER BY pb.bidNumber DESC";
$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['supplierBids'] = isset($supplierBids[$row['idBid']]) ? $supplierBids[$row['idBid']] : [];
$row['status'] = intval($row['isUsed']) === 1 ? 'used' : $row['status'];
$bids[] = $row;
}
$data['bids'] = $bids;
$data['userType'] = $user->getUserType();
return $data;
}
private function validateBidData($bid){
$messages = [];
$requiredFields = ['idPackage', 'idCustomerInstance', 'idPaymentType', 'startDate', 'endDate', 'fixedPrice', 'principalAmount', 'servicesPrice'];
foreach ($requiredFields as $field) {
if(!property_exists($bid , $field)){
$messages[] = [
'code' => 'error',
'message' => $field.'_REQUIRED'
];
return $messages;
}
}
return $messages;
}
private function linkSupplierBids($idBid, $supplierBids){
global $database;
$data = [];
$sqlValues = "";
foreach ($supplierBids as $supplierBid) {
$sqlValues .= "($idBid, ".$supplierBid->idSupplierBid."),";
}
$sqlValues = rtrim($sqlValues, ',');
$sql = "INSERT INTO ".TABLES['rel_bid_supplier_bids']."
(idBid, idSupplierBid)
VALUES $sqlValues";
$query = $database->query($sql);
if($database->affectedRows() < 1){
$data['messages'][] =[
'code' => 'error',
'message' => 'SUPPLIER_BIDS_NOT_LINKED'
];
}else{
$data['messages'][] = [
'code' => 'success',
'message' => 'SUPPLIER_BIDS_LINKED'
];
}
return $data;
}
public function addBid($bid){
global $database;
$bid = json_decode($bid);
$checkData = $this->validateBidData($bid);
if(!empty($checkData)){
$data['messages'] = $checkData;
return $data;
}
$sql = "SELECT MAX(id) as maxBidId FROM ".TABLES['packages_bids']." ";
$maxVals = $database->fetchResultArray($sql);
$maxId = !empty($maxVals) ? $maxVals[0]['maxBidId'] : 0;
$bid->bidNumber = 10000001 + $maxId;
$sql = "INSERT INTO ".TABLES['packages_bids']."
(bidNumber, idPackage, idCustomerInstance, idPaymentType, startDate, endDate, fixedPrice, principalAmount, servicesPrice)
VALUES(
'".$bid->bidNumber."',
'".$bid->idPackage."',
'".$bid->idCustomerInstance."',
'".$bid->idPaymentType."',
'".$bid->startDate."',
'".$bid->endDate."',
'".$bid->fixedPrice."',
'".$bid->principalAmount."',
'".$bid->servicesPrice."'
)";
$query = $database->query($sql);
if($database->affectedRows() !== 1){
$data['messages'][] =[
'code' => 'error',
'message' => 'SERVER_ERROR'
];
return $data;
}else{
$data['messages'][] = [
'code' => 'success',
'message' => 'BID_ADDED'
];
}
$newBidId = $database->getInsertId();
if(property_exists($bid , 'supplierBids') && !empty($bid->supplierBids)){
$insrtSupplierBidsMessage = $this->linkSupplierBids($newBidId, $bid->supplierBids);
$data['messages'] = array_merge($data['messages'], $insrtSupplierBidsMessage['messages']);
}
return $data;
}
public function removeBid($idBid){
global $database;
$data = [];
if(!$idBid){
$data['messages'][] =[
'code' => 'error',
'message' => 'BID_REQUIRED'
];
return $data;
}
$database->beginTransaction();
$affectedRows = 0;
$sql = "DELETE FROM ".TABLES['rel_bid_supplier_bids']."
WHERE idBid=".$database->escapeValue($idBid);
$query = $database->query($sql);
$affectedRows = $database->affectedRows();
$sql = "DELETE FROM ".TABLES['packages_bids']."
WHERE id=".$database->escapeValue($idBid);
$query = $database->query($sql);
$affectedRows += $database->affectedRows();
if($affectedRows < 1){
$database->rollback();
$data['messages'][] =[
'code' => 'error',
'message' => 'SERVER_ERROR'
];
return $data;
}else{
$database->commit();
$data['messages'][] = [
'code' => 'success',
'message' => 'BID_REMOVED'
];
}
return $data;
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* BidssController controls the actions for bids
*/
class BidsController{
private $model;
function __construct(){
$this->model = new BidsModel();
}
/**
* get bids for bids view
* @return json list of bids
*/
public function getBids(){
$filter = isset($_REQUEST['filter']) ? $_REQUEST['filter'] : '[]';
echo json_encode($this->model->getBids($filter), JSON_NUMERIC_CHECK);
}
public function removeBid(){
$idBid = isset($_REQUEST['idBid']) ? $_REQUEST['idBid'] : 0;
echo json_encode($this->model->removeBid($idBid), JSON_NUMERIC_CHECK);
}
public function getClCustomers(){
echo json_encode($this->model->getClCustomers(), JSON_NUMERIC_CHECK);
}
public function getPayTypes(){
$idCommercialLead = isset($_REQUEST['idCommercialLead']) ? $_REQUEST['idCommercialLead'] : 0;
$idCustomer = isset($_REQUEST['idCustomer']) ? $_REQUEST['idCustomer'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->getPayTypes($idCommercialLead, $idCustomer, $idPackage), JSON_NUMERIC_CHECK);
}
public function getPackages(){
$idCommercialLead = isset($_REQUEST['idCommercialLead']) ? $_REQUEST['idCommercialLead'] : 0;
$idCustomer = isset($_REQUEST['idCustomer']) ? $_REQUEST['idCustomer'] : 0;
echo json_encode($this->model->getPackages($idCommercialLead, $idCustomer), JSON_NUMERIC_CHECK);
}
public function getSuppliers(){
echo json_encode($this->model->getSuppliers(), JSON_NUMERIC_CHECK);
}
public function getProducts(){
$idSupplier = isset($_REQUEST['idSupplier']) ? $_REQUEST['idSupplier'] : 0;
echo json_encode($this->model->getProducts($idSupplier), JSON_NUMERIC_CHECK);
}
public function addSupplierBid(){
$supplierBid = isset($_REQUEST['supplierBid']) ? $_REQUEST['supplierBid'] : '[]';
echo json_encode($this->model->addSupplierBid($supplierBid), JSON_NUMERIC_CHECK);
}
public function getUnlinkedSupplierBids() {
echo json_encode($this->model->getUnlinkedSupplierBids(), JSON_NUMERIC_CHECK);
}
public function addBid(){
$bid = isset($_REQUEST['bid']) ? $_REQUEST['bid'] : '[]';
echo json_encode($this->model->addBid($bid), JSON_NUMERIC_CHECK);
}
public function addBidMargin() {
$idBid = isset($_REQUEST['idBid']) ? $_REQUEST['idBid'] : 0;
$bidMargin = isset($_REQUEST['bidMargin']) ? $_REQUEST['bidMargin'] : '[]';
echo json_encode($this->model->addBidMargin($idBid, $bidMargin), JSON_NUMERIC_CHECK);
}
/**
* include bids template
*/
public function bidsViewTemplate(){
global $user;
require_once('templates/BidsViewTemplate.php');
}
/**
* include bids add template
*/
public function addBidTemplate(){
require_once('templates/AddBidTemplate.php');
}
public function addBidMarginTemplate(){
require_once('templates/AddBidMarginTemplate.php');
}
/**
* include bids template
*/
public function bidsTemplate(){
global $user;
require_once('templates/BidsTemplate.php');
}
public function showPage(){
require_once('BidsPage.php');
}
}

View File

@@ -0,0 +1,70 @@
<?php
class BidsModel{
public function getBids($filter){
$bidsHandler = new Bids();
return $bidsHandler->getBids($filter);
}
public function removeBid($idBid){
$bidsHandler = new Bids();
return $bidsHandler->removeBid($idBid);
}
public function getClCustomers(){
$clCustomersHandler = new ClCustomers();
return $clCustomersHandler->getClAndCustomers();
}
public function getPayTypes($idCommercialLead, $idCustomer, $idPackage){
$packages = new Packages();
$data['prices'] = $packages->getPricesForPackages($idCommercialLead, $idPackage, 1, 0, $idCustomer);
$data['prices'] = isset($data['prices'][$idPackage]) ? $data['prices'][$idPackage] : [];
return $data['prices'];
}
public function getPackages($idCommercialLead, $idCustomer){
$customerPackagesHandler = new CustomerPackages();
return $customerPackagesHandler->getShopPackages($idCommercialLead, $idCustomer);
}
public function getSuppliers(){
$supplierBidsHandler = new SupplierBids;
return $supplierBidsHandler->getSuppliers();
}
public function getProducts($idSupplier){
$supplierBidsHandler = new SupplierBids;
return $supplierBidsHandler->getProducts($idSupplier);
}
public function addSupplierBid($supplierBid){
$supplierBidsHandler = new SupplierBids;
return $supplierBidsHandler->addSupplierBid($supplierBid);
}
public function getUnlinkedSupplierBids(){
$supplierBidsHandler = new SupplierBids;
return $supplierBidsHandler->getUnlinkedSupplierBids();
}
public function addBid($bid){
$bidsHandler = new Bids();
return $bidsHandler->addBid($bid);
}
public function addBidMargin($idBid, $bidMargin){
$bidMarginHandler = new BidMargin();
return $bidMarginHandler->addBidMargin($idBid, $bidMargin);
}
}

View File

@@ -0,0 +1,12 @@
<script src="<?php echo PATH_JS_COMPONENTS.'bids/bids.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'bids/bids-view.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'bids/add-bid.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'bids/add-supplier-bid.controller.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'bids/link-supplier-bids.controller.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'bids/add-bid-margin.controller.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'bids/remove-bid.controller.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<div id="bids-module" class="container-fluid col-md-12">
<h1>{{ 'bids.TITLE' | translate }}</h1>
<bids ng-controller="bidsCtrl"></bids>
</div>

View File

@@ -0,0 +1,161 @@
<?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);
}
private function validateBidData($bid){
$messages = [];
$requiredFields = ['idProduct', 'bidNumber'];
foreach ($requiredFields as $field) {
if(!property_exists($bid , $field)){
$messages[] = [
'code' => 'error',
'message' => $field.'_REQUIRED'
];
return $messages;
}
}
return $messages;
}
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);
$checkData = $this->validateBidData($supplierBid);
if(!empty($checkData)){
$data['messages'] = $checkData;
return $data;
}
$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;
}
public function getOrderSupplierBids($idOrder){
global $database;
$data = [];
$idOrder = $database->escapeValue($idOrder);
$sql = "SELECT
sb.id AS idSupplierBid,
sb.bidNumber,
sb.idProduct,
p.productName,
s.id AS idSupplier,
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
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rbsb.idBid=rop.idBid
WHERE rop.idOrder=$idOrder
";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idSupplier']][] = $row;
}
return $data;
}
}

View File

@@ -0,0 +1,29 @@
<div id="add-bid-margin">
<form>
<div class="form-group">
<label for="bidNumber">{{ 'bids.labels.BID_NUMBER' | translate }}</label>
<span>{{bid.bidNumber}}</span>
</div>
<div class="form-group">
<label for="fixedExtra">{{ 'bids.labels.fixedExtra' | translate }}</label>
<input type="text" class="form-control"
id="fixedExtra" placeholder="{{ 'bids.labels.fixedExtra' | translate }}"
ng-model="bidMargin.fixedExtra">
</div>
<div class="form-group">
<label for="recurrentExtra">{{ 'bids.labels.recurrentExtra' | translate }}</label>
<input type="text" class="form-control"
id="recurrentExtra" placeholder="{{ 'bids.labels.recurrentExtra' | translate }}"
ng-model="bidMargin.recurrentExtra">
</div>
<div class="form-group">
<label for="servicesExtra">{{ 'bids.labels.servicesExtra' | translate }}</label>
<input type="text" class="form-control"
id="servicesExtra" placeholder="{{ 'bids.labels.servicesExtra' | translate }}"
ng-model="bidMargin.servicesExtra">
</div>
</form>
</div>

View File

@@ -0,0 +1,90 @@
<div id="add-bid" class="row">
<form>
<div class="col-lg-4">
<div class="form-group">
<label for="idCommercialLead">{{ 'bids.labels.COMEMRCIAL_LEADS' | translate }}</label>
<select class="form-control"
id="idCommercialLead" placeholder="{{ 'bids.labels.COMEMRCIAL_LEADS' | translate }}"
ng-options="option.commercialLead for option in clCustomers track by option.idCommercialLead"
ng-change="onCLSelect()"
ng-model="selectedCl"></select>
</div>
<div class="form-group">
<label for="idCustomerInstance">{{ 'bids.labels.CUSTOMER' | translate }}</label>
<select class="form-control"
id="idCustomerInstance" placeholder="{{ 'bids.labels.CUSTOMER' | translate }}"
ng-options="option.customer for option in selectedCl.customers track by option.idCustomerInstance"
ng-change="onCustomerSelect()"
ng-model="selectedCustomer"></select>
</div>
<div class="form-group">
<label for="idPackage">{{ 'bids.labels.PACKAGE' | translate }}</label>
<select class="form-control"
id="idPackage" placeholder="{{ 'bids.labels.PACKAGE' | translate }}"
ng-options="option.packageName for option in packages track by option.idPackage"
ng-change="onPackageSelect()"
ng-model="selectedPackage"></select>
</div>
<div class="form-group">
<label for="idPaymentType">{{ 'bids.labels.PAY_TYPE' | translate }}</label>
<select class="form-control"
id="idPaymentType" placeholder="{{ 'bids.labels.PAY_TYPE' | translate }}"
ng-options="option.payType for option in payTypes track by option.idPaymentType"
ng-change="onPayTypeSelect()"
ng-model="selectedPayType"></select>
</div>
<div class="form-group">
<label for="startDate">{{ 'bids.labels.START_DATE' | translate }}</label>
<input type="text" class="form-control"
id="startDate" placeholder="{{ 'bids.labels.START_DATE' | translate }}"
datepicker
ng-model="bid.startDate">
</div>
<div class="form-group">
<label for="endDate">{{ 'bids.labels.END_DATE' | translate }}</label>
<input type="text" class="form-control"
id="endDate" placeholder="{{ 'bids.labels.END_DATE' | translate }}"
datepicker
ng-model="bid.endDate">
</div>
</div>
<div class="col-lg-4">
<div class="form-group">
<label for="fixedPrice">{{ 'bids.labels.FIXED' | translate }}</label>
<input type="text" class="form-control"
id="fixedPrice" placeholder="{{ 'bids.labels.FIXED' | translate }}"
ng-model="bid.fixedPrice">
</div>
<div class="form-group">
<label for="principalAmount">{{ 'bids.labels.PRINCIPAL_AMOUNT' | translate }}</label>
<input type="text" class="form-control"
id="principalAmount" placeholder="{{ 'bids.labels.PRINCIPAL_AMOUNT' | translate }}"
ng-model="bid.principalAmount">
</div>
<div class="form-group">
<label for="servicesPrice">{{ 'bids.labels.SERVICES' | translate }}</label>
<input type="text" class="form-control"
id="servicesPrice" placeholder="{{ 'bids.labels.SERVICES' | translate }}"
ng-model="bid.servicesPrice">
</div>
<?php include('LinkedBidsTemplate.php'); ?>
</div>
<div class="col-lg-12">
<div class="form-group">
<div ng-click="saveBid()" class="btn btn-primary">
{{ 'bids.buttons.SAVE_BID' | translate }}
</div>
</div>
</div>
</form>
</div>

View File

@@ -0,0 +1,28 @@
<div id="add-supplier-bid" ng-int="getSuppliers()">
<form>
<div class="form-group">
<label for="idSupplier">{{ 'bids.labels.SUPPLIER' | translate }}</label>
<select class="form-control"
id="idSupplier" placeholder="{{ 'bids.labels.SUPPLIER' | translate }}"
ng-options="option.supplier for option in suppliers track by option.idSupplier"
ng-change="onSupplierSelect()"
ng-model="selectedSupplier"></select>
</div>
<div class="form-group">
<label for="idProduct">{{ 'bids.labels.PRODUCT' | translate }}</label>
<select class="form-control"
id="idProduct" placeholder="{{ 'bids.labels.PRODUCT' | translate }}"
ng-options="option.productName for option in products track by option.idProduct"
ng-change="onProductSelect()"
ng-model="selectedProduct"></select>
</div>
<div class="form-group">
<label for="bidNumber">{{ 'bids.labels.BID_NUMBER' | translate }}</label>
<input type="text" class="form-control"
id="bidNumber" placeholder="{{ 'bids.labels.BID_NUMBER' | translate }}"
ng-model="supplierBid.bidNumber">
</div>
</form>
</div>

View File

@@ -0,0 +1,19 @@
<div ng-if="bid.isUsed !== 1">
<div ng-click="showBidMarginDialog(bid.idBid)" class="add-bid-margin-btn btn btn-primary">
{{ 'bids.buttons.EDIT_MARGINS' | translate }}
</div>
</div>
<div ng-if="isMarginsDialogVisible[bid.idBid]" ng-controller="addBidMarginCtrl">
<div id="dialog-add-bid-margin-{{bid.idBid}}"
dialog
is-modal="true"
has-buttons="true"
on-confirmation="saveBidMargin"
on-close="closeBidMarginDialog"
parameters="{bid, getBids}"
buttons-names="{confirmation: 'Add Margin', cancel: 'Cancel'}"
title="{{'bids.headers.ADD_BID_MARGIN' | translate}}">
<add-bid-margin ng-init="init(bid)"/>
</div>
</div>

View File

@@ -0,0 +1,19 @@
<div ng-if="bid.isUsed !== 1">
<div ng-click="showBidRemoveDialog(bid.idBid)" class="remove-bid-btn btn btn-danger">
{{ 'bids.buttons.REMOVE' | translate }}
</div>
</div>
<div ng-if="isRemoveDialogVisible[bid.idBid]" ng-controller="removeBidCtrl">
<div id="dialog-remove-bid-{{bid.idBid}}"
dialog
is-modal="true"
has-buttons="true"
on-confirmation="removeBid"
on-close="closeRemoveDialog"
parameters="{bid, getBids}"
buttons-names="{confirmation: 'Yes', cancel: 'Cancel'}"
title="{{'bids.headers.REMOVE_BID' | translate}}">
{{'bids.labels.REMOVE_BID_LABEL' | translate}} {{bid.bidNumber}}?
</div>
</div>

View File

@@ -0,0 +1,9 @@
<?php
if($user->getUserType() === USER_TYPES['BROKER']){
include('BidsTemplateBroker.php');
}
if($user->getUserType() === USER_TYPES['COMMERCIAL_LEAD']){
include('BidsTemplateCommercialLead.php');
}

View File

@@ -0,0 +1,27 @@
<button type="button"
id="bids-view-btn"
subModule="bidsView"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'bids.buttons.VIEW_BIDS' | translate }}</button>
<button type="button"
id="bids-add-btn"
subModule="bidAdd"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'bids.buttons.ADD_BID' | translate }}</button>
<div class="row">
<div class="col-md-12"
id="bids-view-layer"
ng-if="isSubmoduleVisible('bidsView')">
<bids-view ng-controller="bidsViewCtrl" ng-init="getBids()"></bids-view>
</div>
</div>
<div class="row">
<div class="col-md-12"
id="bid-add-layer"
ng-if="isSubmoduleVisible('bidAdd')">
<add-bid ng-controller="addBidCtrl" ng-init="initAddBid()"></add-bid>
</div>
</div>

View File

@@ -0,0 +1,14 @@
<button type="button"
id="bids-view-btn"
subModule="bidsView"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'bids.buttons.VIEW_BIDS' | translate }}</button>
<div class="row">
<div class="col-md-12"
id="bids-view-layer"
ng-if="isSubmoduleVisible('bidsView')">
<bids-view ng-controller="bidsViewCtrl" ng-init="getBids()"></bids-view>
</div>
</div>

View File

@@ -0,0 +1,110 @@
<div id="bids-view">
<div class="row bids-fitlers">
<div class="col-lg-3">
Search: <input ng-model="searchText" ng-change="filterBids('search')"/>
</div>
<div class="col-lg-5">
Bid type:
<select ng-change="filterBids(bidType)" ng-model="bidType">
<option value='all'>All</option>
<option value='available'>Available</option>
<option value='used'>Used</option>
<option value='expired'>Expired</option>
</select>
</div>
</div>
<div class="row bids-list">
<div class="col-xl-4 col-lg-4 col-md-6 col-sm-12" ng-repeat="bid in filteredBids">
<div class="bid-item {{bid.status}}">
<div class="bid-number">
<h4 class="col-lg-12">Bid: {{bid.bidNumber}} <span class="bid-date">( {{bid.startDate}} - {{bid.endDate}} )</span></h4>
</div>
<div class="bid-reference">
<div class="{{HEADER_COL}}">
Package:
</div>
<div class="{{LABEL_COL}}">
{{bid.packageName}}
</div>
<div class="{{HEADER_COL}}">
Sold by:
</div>
<div class="{{LABEL_COL}}">
{{bid.commercialLead}}
</div>
<div class="{{HEADER_COL}}">
Customer:
</div>
<div class="{{LABEL_COL}}">
{{bid.customer}}
</div>
</div>
<div class="bid-pay-type">
<div class="{{HEADER_COL}}">
Pay Type:
</div>
<div class="{{LABEL_COL}}">
{{bid.payType}}
</div>
</div>
<div class="bid-price">
<div class="{{HEADER_COL}}">
Fixed:
</div>
<div class="{{LABEL_COL}}">
{{bid.fixedPrice}}
<span ng-if="isCommercialLead">+ {{bid.fixedExtra}} = {{(bid.fixedPrice + bid.fixedExtra).toFixed(2)}}</span>
</div>
<div class="{{HEADER_COL}}">
Recurrent:
</div>
<div class="{{LABEL_COL}}">
{{bid.recurrentPrice}}
<span ng-if="isCommercialLead">+ {{bid.recurrentExtra}} = {{(bid.recurrentPrice + bid.recurrentExtra).toFixed(2)}}</span>
</div>
<div class="{{HEADER_COL}}">
Services:
</div>
<div class="{{LABEL_COL}}">
{{bid.servicesPrice}}
<span ng-if="isCommercialLead">+ {{bid.servicesExtra}} = {{(bid.servicesPrice + bid.servicesExtra).toFixed(2)}}</span>
</div>
</div>
<div class="bid-status">
<div class="{{HEADER_COL}} {{bid.status}}-status">
Status:
</div>
<div class="{{LABEL_COL}} {{bid.status}}-status">
{{bid.status}}
</div>
</div>
<div class="supplier-bids">
<div class="{{HEADER_COL}}">
Supplier Bids:
</div>
<div class="{{LABEL_COL}}">
<div ng-if="bid.supplierBids.length === 0">-</div>
<div
ng-repeat="supllierBid in bid.supplierBids">
{{supllierBid.bidNumber}} {{supllierBid.supplier}} {{supllierBid.productName}},
</div>
</div>
</div>
<?php
if($user->getUserType() === USER_TYPES['COMMERCIAL_LEAD']){
include('BidsAddMarginButton.php');
}
?>
<?php
if($user->getUserType() === USER_TYPES['BROKER']){
include('BidsRemoveButton.php');
}
?>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
<div id="link-supplier-bids" ng-init="getUnlinkedSupplierBids()">
<div class="supplier-bids-list row">
<div class="supplier-bid-header col-lg-12">
<div class="col col-lg-4">{{ 'bids.labels.BID_NUMBER' | translate }}</diV>
<div class="col col-lg-4">{{ 'bids.labels.SUPPLIER' | translate }}</diV>
<div class="col col-lg-4">{{ 'bids.labels.PRODUCT' | translate }}</diV>
</div>
<div class="supplier-bid col-lg-12 {{supplierBid.class}}"
ng-click="onSupBidSelect(supplierBid)"
ng-repeat="supplierBid in supplierBids">
<div class="col col-lg-4">
{{supplierBid.bidNumber}}
</div>
<div class="col col-lg-4">
{{supplierBid.supplier}}
</div>
<div class="col col-lg-4">
{{supplierBid.productName}}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,43 @@
<div>
<div class="form-group">
<div>
<label>{{ 'bids.labels.SUPPLIER_BIDS' | translate }}</label>
<span class="selected-supplier-bid" ng-repeat="supplierBid in bid.supplierBids">{{supplierBid.bidNumber}}, </span>
</div>
<div>
<div ng-click="showLinkBidDialog()" class="btn btn-primary">
{{ 'bids.buttons.LINK_BID' | translate }}
</div>
<div ng-click="showSupBidDialog()" class="btn btn-primary">
{{ 'bids.buttons.ADD_BID' | translate }}
</div>
</div>
</div>
<div ng-if="isLinkSupBidDialogVisible" ng-controller="linkSupplierBidsCtrl" ng-init="init(bid.supplierBids)">
<div id="dialog-link-supplier-bid"
dialog
is-modal="true"
has-buttons="true"
on-confirmation="$parent.linkSuppliers"
on-close="showLinkBidDialog"
parameters="{selectedBids}"
buttons-names="{confirmation: 'Link Supplier Bids', cancel: 'Cancel'}"
title="{{'bids.headers.LINK_SUPPLIER_BIDS' | translate}}">
<?php include('LinkSupplierBidsTemplate.php'); ?>
</div>
</div>
<div ng-if="isAddSupBidDialogVisible" ng-controller="addSupplierBidCtrl">
<div id="dialog-add-supplier-bid"
dialog
is-modal="true"
has-buttons="true"
on-confirmation="saveSupplierBid"
on-close="showSupBidDialog"
buttons-names="{confirmation: 'Add Supplier Bid', cancel: 'Cancel'}"
title="{{'bids.headers.SUPPLIER_BID' | translate}}">
<?php include('AddSupplierBidTemplate.php'); ?>
</div>
</div>
</div>

View File

@@ -0,0 +1,34 @@
<?php
/**
* Controller for contact page
*/
class ContactController{
private $model;
function __construct(){
$this->model = new ContactModel();
}
/**
* get contact information
* @return json list of contacts
*/
public function getContactInfo(){
echo json_encode($this->model->getContactInfo());
}
/**
* include contact template
*/
public function contactTemplate(){
global $user;
require_once('templates/ContactTemplate.php');
}
/**
* open contact page
*/
public function showPage(){
require_once('ContactPage.php');
}
}

View File

@@ -0,0 +1,257 @@
<?php
/**
*ata manipulation for contact page
*/
class ContactModel{
/**
* get contact information based on user type
* @return array list of contacts based on the user type
*/
public function getContactInfo(){
global $user;
$userType = ucfirst($user->getUserType());
$method = 'getContactFor'.$userType;
$method = str_replace("_", "", $method);
if(method_exists ($this, $method)){
return $this->{$method}();
}else{
trigger_error("No contact for this user type!", E_USER_ERROR);
}
}
/**
* [getAddresses description]
* @param String $userType the type of the user
* @return Array list of addresses based on user type
*/
public function getAddresses($userType){
global $database, $user;
$extraJoin = "";
if($userType === USER_TYPES['BROKER']){
$extraJoin .= "INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.idUser=a.idUser";
}
if($userType === USER_TYPES['COMMERCIAL_LEAD']){
$extraJoin .= "INNER JOIN
(SELECT
b.idUser
FROM ".TABLES['brokers']." b
UNION ALL
SELECT c.idUser
FROM ".TABLES['customers']." c
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.idCustomer=c.id
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.id=rclc.idCommercialLead
WHERE cl.idUser=".$user->getUserId()." AND rclc.isLinkEnabled=1
) users
ON users.idUser=a.idUser";
}
if($userType === USER_TYPES['CUSTOMER']){
$extraJoin .= "INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.idUser=a.idUser
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.idCommercialLead=cl.id AND rclc.isLinkEnabled=1
INNER JOIN ".TABLES['customers']." cust
ON cust.id=rclc.idCustomer AND cust.idUser=".$user->getUserId();
}
$sql = "SELECT
a.idUser,
a.company,
a.firstName,
a.lastName,
a.city,
a.detailedAddress,
a.zip,
c.name as country
FROM ".TABLES['billing_information']." a
INNER JOIN ".TABLES['countries']." c
ON c.id=a.idCountry
$extraJoin";
$data = [];
$query = $database->query($sql);
while($row=$database->fetchArray($query)){
$data[$row['idUser']][] = $row;
}
return $data;
}
private function getSellCountries($userType){
global $database, $user;
$extraJoin = "";
if($userType === USER_TYPES['CUSTOMER']){
$extraJoin .= "INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.idCommercialLead=plcl.idCommercialLead AND rclc.isLinkEnabled=1
INNER JOIN ".TABLES['customers']." cust
ON cust.id=rclc.idCustomer AND cust.idUser=".$user->getUserId();
}
if($userType === USER_TYPES['COMMERCIAL_LEAD']){
$sql ="SELECT DISTINCT
c.name,
c.code,
0 AS idUserByType
FROM ".TABLES['countries']." c
INNER JOIN ".TABLES['packages']." p
ON p.idCountry=c.id
INNER JOIN ".TABLES['price_list_broker']." plb
ON plb.idPackage=p.id
ORDER BY c.name";
}else{
$sql ="SELECT DISTINCT
c.name,
c.code,
plcl.idCommercialLead AS idUserByType
FROM ".TABLES['countries']." c
INNER JOIN ".TABLES['packages']." p
ON p.idCountry=c.id
INNER JOIN ".TABLES['price_list_commercial_lead']." plcl
ON plcl.idPackage=p.id
$extraJoin
ORDER BY c.name";
}
$data = [];
$query = $database->query($sql);
while($row=$database->fetchArray($query)){
$data[$row['idUserByType']][] = $row;
}
return $data;
}
/**
* get contatc informations for brokers
* @return array list of contacts for broker
*/
public function getContactForBroker(){
global $database, $user;
$addresses = $this->getAddresses($user->getUserType());
$countries = $this->getSellCountries($user->getUserType());
$sql = "SELECT
cl.id as idCommercialLead,
cl.name,
cl.phone,
u.mail,
cl.idUser
FROM ".TABLES['commercial_leads']." cl
INNER JOIN ".TABLES['users']." u
ON u.id=cl.idUser
ORDER BY cl.name";
$data = [];
$query = $database->query($sql);
while($row=$database->fetchArray($query)){
$row['addresses'] = isset($addresses[$row['idUser']]) ? $addresses[$row['idUser']] : [];
unset($row['idUser']);
$row['countries'] = isset($countries[$row['idCommercialLead']]) ? $countries[$row['idCommercialLead']] : [];
unset($row['idCommercialLead']);
$data[] = $row;
}
return $data;
}
/**
* get contact information for customers
* @return array list of contacts for customers
*/
public function getContactForCustomer(){
global $database, $user;
$addresses = $this->getAddresses($user->getUserType());
$countries = $this->getSellCountries($user->getUserType());
$sql = "SELECT
cl.id AS idCommercialLead,
cl.name,
cl.phone,
cl.mail,
cl.idUser,
cl.vatCode
FROM ".TABLES['commercial_leads']." cl
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.idCommercialLead=cl.id AND rclc.isLinkEnabled=1
INNER JOIN ".TABLES['customers']." c
ON c.id=rclc.idCustomer
WHERE c.idUser=".$user->getUserId()."
ORDER BY cl.name";
$data = [];
$query = $database->query($sql);
while($row=$database->fetchArray($query)){
$row['addresses'] = isset($addresses[$row['idUser']]) ? $addresses[$row['idUser']] : [];
unset($row['idUser']);
$row['countries'] = isset($countries[$row['idCommercialLead']]) ? $countries[$row['idCommercialLead']] : [];
unset($row['idCommercialLead']);
$data[] = $row;
}
return $data;
}
/**
* get contact informations for commercial lead
* @return array list of contacts for commercial lead
*/
public function getContactForCommerciallead(){
global $database, $user;
$addresses = $this->getAddresses($user->getUserType());
$countries = $this->getSellCountries($user->getUserType());
$sql = "SELECT
b.id AS idByUserType,
b.name,
b.phone,
u.mail,
b.idUser,
'brokers' AS type
FROM ".TABLES['brokers']." b
INNER JOIN ".TABLES['users']." u
ON u.id=b.idUser
UNION ALL
SELECT
0 AS idByUserType,
c.name,
c.phone,
u.mail,
c.idUser,
'customers' AS type
FROM ".TABLES['customers']." c
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.idCustomer=c.id AND rclc.isLinkEnabled=1
INNER JOIN ".TABLES['commercial_leads']." cl
ON cl.id=rclc.idCommercialLead
INNER JOIN ".TABLES['users']." u
ON u.id=c.idUser
WHERE cl.idUser=".$user->getUserId()."
ORDER BY type,name";
$data = [];
$query = $database->query($sql);
while($row=$database->fetchArray($query)){
$row['addresses'] = isset($addresses[$row['idUser']]) ? $addresses[$row['idUser']] : [];
unset($row['idUser']);
if($row['idByUserType'] != 0){
$row['countries'] = isset($countries[0]) ? $countries[0] : [];
}
unset($row['idByUserType']);
$data[$row['type']][] = $row;
}
return $data;
}
}

View File

@@ -0,0 +1,5 @@
<script src="<?php echo PATH_JS_COMPONENTS.'contact/contact-page.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<div id="contact-module" class="container-fluid col-md-12">
<contact-page ng-controller="contactPageCtrl" ng-init="getContactInfo()"></contact-page>
</div>

View File

@@ -0,0 +1,50 @@
<div id="contact-info-{{type}}" class="col-md-12" ng-repeat="(type, users) in contactInfo">
<h3>{{'contact.headers.' + type.toUpperCase() | translate}}</h3>
<div class="contact-big-box col-md-4" ng-repeat="user in users">
<div class="contact-info-layer">
<h3 class="contact-info-title">
<div class="info-icon glyphicon glyphicon-briefcase"></div>
<div class="info-big-text">{{user.name}}</div>
</h3>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon-earphone"></div>
<div class="info-text">{{user.phone}}</div>
</div>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon-envelope"></div>
<div class="info-text">{{user.mail}}</div>
</div>
<div class="contact-info-box" ng-if="user.countries.length">
<div class="info-icon glyphicon glyphicon-globe"></div>
<div class="info-text">
<div class="contact-info-country" ng-repeat="country in user.countries">
{{country.name}} <span class="flag-icon flag-icon-{{country.code}}"></span>&nbsp;
</div>
</div>
</div>
<div ng-if="user.addresses.length" class="contact-info-addresses-layer">
<h4><div class="info-big-text">{{'contact.headers.BILLING_INFORMATIONS' | translate}}</div></h4>
<div class="contact-info-address" ng-repeat="address in user.addresses">
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon glyphicon-home"></div>
<div class="info-text">{{address.company}}</div>
</div>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon glyphicon-user"></div>
<div class="info-text">{{address.firstName}} {{address.lastName}}</div>
</div>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon-map-marker"></div>
<div class="info-text">{{address.country}}, {{address.detailedAddress}}, zip {{address.zip}}</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,57 @@
<div id="contact-info-commercial-leads" class="col-md-12">
<h3>{{'contact.headers.COMMERCIAL_LEADS' | translate}}</h3>
<div class="contact-big-box col-md-4" ng-repeat="commercialLead in contactInfo">
<div class="contact-info-layer">
<h3 class="contact-info-title">
<div class="info-icon glyphicon glyphicon-briefcase"></div>
<div class="info-big-text">{{commercialLead.name}}</div>
</h3>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon-earphone"></div>
<div class="info-text">{{commercialLead.phone}}</div>
</div>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon-envelope"></div>
<div class="info-text">{{commercialLead.mail}}</div>
</div>
<div class="contact-info-box" ng-if="commercialLead.countries.length">
<div class="info-icon glyphicon glyphicon-globe"></div>
<div class="info-text">
<div class="contact-info-country" ng-repeat="country in commercialLead.countries">
{{country.name}} <span class="flag-icon flag-icon-{{country.code}}"></span>&nbsp;
</div>
</div>
</div>
<div ng-if="commercialLead.addresses.length" class="contact-info-addresses-layer">
<h4><div class="info-big-text">{{'contact.headers.BILLING_INFORMATIONS' | translate}}</div></h4>
<div class="contact-info-address" ng-repeat="address in commercialLead.addresses">
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon glyphicon-home"></div>
<div class="info-text">{{address.company}}</div>
</div>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon glyphicon-user"></div>
<div class="info-text">{{address.firstName}} {{address.lastName}}</div>
</div>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon-map-marker"></div>
<div class="info-text">{{address.country}}, {{address.detailedAddress}}, zip {{address.zip}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<?php
if($user->getUserType() === USER_TYPES['BROKER']){
require_once('ContactSupportTemplate.php');
}
?>

View File

@@ -0,0 +1,16 @@
<div id="contact-info-support" class="col-md-12">
<h3>{{'contact.headers.SUPPORT' | translate}}</h3>
<div class="contact-big-box col-md-4">
<div class="contact-info-layer">
<h3 class="contact-info-title">
<div class="info-icon glyphicon glyphicon-cog"></div>
<div class="info-big-text">{{'contact.headers.SUPPORT' | translate}}</div>
</h3>
<div class="contact-info-box">
<div class="info-icon glyphicon glyphicon-envelope"></div>
<div class="info-text"><?php echo SUPPORT_MAIL_LIST[0]; ?></div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,8 @@
<?php
if($user->getUserType() === USER_TYPES['CUSTOMER'] || $user->getUserType() === USER_TYPES['BROKER']){
require_once('ContactCustomerAndBrokerTemplate.php');
}
if($user->getUserType() === USER_TYPES['COMMERCIAL_LEAD']){
require_once('ContactCommercialLeadTemplate.php');
}

View File

@@ -0,0 +1,24 @@
<?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] : '';
}
}

View File

@@ -0,0 +1,21 @@
<?php
/**
* CountriesController controls the actions for countries
*/
class CountriesController{
private $model;
function __construct(){
$this->model = new CountriesModel();
}
/**
* returns json response for countries
* @return list all countries json
*/
public function getAllCountries(){
$getArray = isset($_REQUEST['getArray']) ? $_REQUEST['getArray'] : false;
echo json_encode($this->model->getAllCountries($getArray));
}
}
?>

View File

@@ -0,0 +1,29 @@
<?php
class CountriesModel{
/**
* get the list of all countries
* @return Array of countries
*/
public function getAllCountries($getArray = false){
global $database;
$sql = "SELECT
id,
name
FROM " . TABLES['countries']."
ORDER BY name";
$countriesArray = $database->fetchResultArray($sql);
if($getArray) {
return $countriesArray;
}
foreach($countriesArray as $countryInfo) {
$countries[$countryInfo['id']] = $countryInfo['name'];
}
return $countries;
}
}
?>

View File

@@ -0,0 +1,121 @@
<?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 getClAndCustomers(){
global $database, $user;
$data = [];
$sql = "SELECT
rclc.id as idCustomerInstance,
cl.name as commercialLead,
cl.id as idCommercialLead,
c.id AS idCustomer,
c.name AS customer,
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) clCompany
ON clCompany.id = cl.idUser
ORDER BY cl.name
";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
if(!isset($data[$row['idCommercialLead']])){
$data[$row['idCommercialLead']] = [];
}
$data[$row['idCommercialLead']]['idCommercialLead'] = $row['idCommercialLead'];
$data[$row['idCommercialLead']]['commercialLead'] = $row['commercialLead'];
$data[$row['idCommercialLead']]['customers'][] = $row;
}
$data = (array) $data;
usort($data, function($clA, $clB) {
return strnatcasecmp($clA['commercialLead'], $clB['commercialLead']) > 0 ? 1 : -1;
});
return $data;
}
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,67 @@
<?php
/**
* Cusotmers controlls the actions for customers
*/
class CustomersController{
private $model;
function __construct(){
$this->model = new CustomersModel();
}
/**
* get all commecrial lead customers linked to package
* @return json list with commercial lead customers
*/
public function getComercialLeadCustomers(){
echo json_encode($this->model->getComercialLeadCustomers());
}
/**
* returns all the order types existing in the application
* @return Array with all order types
*/
public function getOrderTypes() {
echo json_encode($this->model->getOrderTypes());
}
/**
* save default order type for cl
* @return Array update emssage
*/
public function saveDefaultOrderType() {
$defaultIdOrderType = isset($_REQUEST['defaultIdOrderType']) ? $_REQUEST['defaultIdOrderType'] : 0;
echo json_encode($this->model->saveDefaultOrderType($defaultIdOrderType));
}
/**
* dave order type for each custoemr
* @return Array update message
*/
public function saveCustomersOrderTypes() {
$customers = isset($_REQUEST['customers']) ? $_REQUEST['customers'] : '[]';
echo json_encode($this->model->saveCustomersOrderTypes($customers));
}
/**
* include customers template
*/
public function customersTemplate(){
global $user;
require_once('templates/CustomersTemplate.php');
}
/**
* include custoemrs view template
*/
public function customersViewTemplate(){
require_once('templates/CustomersViewTemplate.php');
}
/**
* open custoemrs page
*/
public function showPage(){
require_once('CustomersPage.php');
}
}

View File

@@ -0,0 +1,51 @@
<?php
/**
* Data manipulation for the docuemnts
*/
class CustomersModel{
/**
* returns all the invoice processes existing in the application
* @return Array all the invoice processes from the application
*/
public function getOrderTypes() {
$orderType = new OrderType();
return $orderType->getOrderTypes();
}
/**
* get customers list linked to the commercial lead
* @return Array list of customers linked to a commercial lead
*/
public function getComercialLeadCustomers(){
$data = [];
$clCustomers = new ClCustomers();
$orderType = new OrderType();
$data['customers'] = $clCustomers->getComercialLeadCustomers();
$data['defaultIdOrderType'] = $orderType->getCLDefaultOrderType();
return $data;
}
/**
* save Default Order Type
* @param INT $defaultIdOrderType id for default order type
* @return Array update message
*/
public function saveDefaultOrderType($defaultIdOrderType){
$orderType = new OrderType();
return $orderType->saveDefaultOrderType($defaultIdOrderType);
}
/**
* 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){
$orderType = new OrderType();
return $orderType->saveCustomersOrderTypes($customers);
}
}

View File

@@ -0,0 +1,7 @@
<script src="<?php echo PATH_JS_COMPONENTS.'customers/customers.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'customers/customers-view.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<div id="customers-module" class="container-fluid col-md-12">
<h1>{{ 'customers.TITLE' | translate }}</h1>
<customers ng-controller="customersCtrl"></customers>
</div>

View File

@@ -0,0 +1,135 @@
<?php
class OrderType{
/**
* 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(){
global $database, $user;
$sql = "SELECT
cl.defaultIdOrderType
FROM ".TABLES['commercial_leads']." cl
WHERE cl.idUser=".$user->getUserId()."
LIMIT 1";
$query = $database->query($sql);
$row = $database->fetchArray($query);
return $row['defaultIdOrderType'];
}
}

View File

@@ -0,0 +1,13 @@
<button type="button"
id="customers-view"
subModule="customersView"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'customers.buttons.VIEW_CUSTOMERS' | translate }}</button>
<div class="row">
<div class="col-md-12"
id="customers-view-layer"
ng-if="isSubmoduleVisible('customersView')">
<customers-view ng-controller="customersViewCtrl" ng-init="viewCustomersIntit()"></customers-view>
</div>
</div>

View File

@@ -0,0 +1,70 @@
<div class="customers-view-layer row">
<div class="row">
<div class="col-md-6 title-header">
<div class="col-md-6">
{{ 'customers.headers.DEFAULT' | translate }}
</div>
<div class="col-md-6">
{{ 'customers.headers.ORDER_TYPE' | translate }}
</div>
</div>
</div>
<div class="row customer-row">
<div class="col-md-6 custom-border">
<div class="col-md-6">
{{ 'customers.headers.DEFAULT' | translate }}
</div>
<div class="col-md-6">
<div ng-repeat="orderType in orderTypes">
<input type="radio" value="{{orderType.idOrderType}}" ng-model="$parent.defaultIdOrderType" name="defaultOrderType"/>
<label>{{orderType.name}}</label>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="btn btn-primary" ng-click="saveDefaultOrderType()">
{{ 'customers.buttons.SAVE' | translate }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 title-header">
<div class="col-md-6">
{{ 'customers.headers.CUSTOMERS' | translate }}
</div>
<div class="col-md-6">
{{ 'customers.headers.ORDER_TYPE' | translate }}
</div>
</div>
</div>
<div class="row customer-row" ng-repeat="customer in customers">
<div class="col-md-6 custom-border">
<div class="col-md-6">
{{customer.customerName}}
<span ng-if="isSameCompany(customer.isSameCompanyAsCl)">(same company)</span>
</div>
<div class="col-md-6">
<div ng-repeat="orderType in orderTypes">
<input type="radio"
value="{{orderType.idOrderType}}"
ng-disabled="isSameCompany(customer.isSameCompanyAsCl)"
ng-model="customer.idOrderType"
name="customer-{{customer.idCustomerInstance}}"/>
<label>{{orderType.name}}</label>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="btn btn-primary" ng-click="saveCustomerOrderTypes()">
{{ 'customers.buttons.SAVE' | translate }}
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,162 @@
<?php
class DashboardsController{
private $model;
function __construct(){
$this->model = new DashboardsModel();
}
/**
* get all user dashborads ( public dashboards are also taken)
* @return json list of dashboards
*/
public function getUserDashboards(){
echo json_encode($this->model->getUserDashboards());
}
/**
* 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 order central gadget
* @return json orders info
*/
public function getOrderCentralInfo(){
$filters = isset($_REQUEST['filters']) ? $_REQUEST['filters'] : '';
$sortBy = isset($_REQUEST['sortBy']) ? $_REQUEST['sortBy'] : '';
echo json_encode($this->model->getOrderCentralInfo($filters, $sortBy));
}
/**
* get data required for assigned orders
* @return json assigned orders info
*/
public function getAssignedOrdersInfo(){
$filters = isset($_REQUEST['filters']) ? $_REQUEST['filters'] : '';
$sortBy = isset($_REQUEST['sortBy']) ? $_REQUEST['sortBy'] : '';
echo json_encode($this->model->getAssignedOrdersInfo($filters, $sortBy));
}
/**
* 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));
}
/**
* get gadgets for creating new dashboards
* @return json list of gadgets
*/
public function getAllGadgets(){
$idDashboard = isset($_REQUEST['idDashboard']) ? $_REQUEST['idDashboard'] : 0;
$selectedUserType = isset($_REQUEST['selectedUserType']) ? $_REQUEST['selectedUserType'] : 0;
echo json_encode($this->model->getAllGadgets($idDashboard, $selectedUserType));
}
/**
* get information for a selected dashboard on creation
* @return json dashborad info
*/
public function getDashboardInfo(){
$idDashboard = isset($_REQUEST['idDashboard']) ? $_REQUEST['idDashboard'] : '';
echo json_encode($this->model->getDashboardInfo($idDashboard));
}
/**
* create a new adshboard
* @return json array containg the success or error messages
*/
public function createDashboard(){
$selectedGadgets = isset($_REQUEST['selectedGadgets']) ? $_REQUEST['selectedGadgets'] : '[]';
$name = isset($_REQUEST['name']) ? $_REQUEST['name'] : '';
$visibility = isset($_REQUEST['visibility']) ? $_REQUEST['visibility'] : '';
$idDashboard = isset($_REQUEST['idDashboard']) ? $_REQUEST['idDashboard'] : 0;
$selectedUserType = isset($_REQUEST['selectedUserType']) ? $_REQUEST['selectedUserType'] : 0;
echo json_encode($this->model->createDashboard($idDashboard, $name, $visibility, $selectedGadgets, $selectedUserType));
}
/**
* get user types
* @return json user types from the system
*/
public function getUserTypes(){
echo json_encode($this->model->getUserTypes());
}
/**
* remove a dashborad
* @return json update message
*/
public function removeDashboard(){
$idDashboard = isset($_REQUEST['idDashboard']) ? $_REQUEST['idDashboard'] : 0;
echo json_encode($this->model->removeDashboard($idDashboard));
}
/**
* get template for view dashboard
*/
public function createDashboardTemplate(){
global $user;
require_once('templates/CreateDashboardTemplate.php');
}
/**
* get template for view dashboard
*/
public function dashboardsViewTemplate(){
require_once('templates/DashboardsViewTemplate.php');
}
/**
* get template for orders central gadget
*/
public function orderCentralTemplate(){
require_once('templates/gadgets/orderCentralTemplate.php');
}
/**
* get template for assigned orders gadget
*/
public function assignedOrdersTemplate(){
require_once('templates/gadgets/assignedOrdersTemplate.php');
}
/**
* get template for orders central gadget
*/
public function nextActionsTemplate(){
require_once('templates/gadgets/nextActionsTemplate.php');
}
/**
* get template for gadgets fiter
*/
public function dashboardsFiltersTemplate(){
require_once('templates/DashboardsFiltersTemplate.php');
}
/**
* get template for dashboards
*/
public function dashboardsTemplate(){
require_once('templates/DashboardsTemplate.php');
}
/**
* show page for dashboards
*/
public function showPage(){
require_once('DashboardsPage.php');
}
}
?>

View File

@@ -0,0 +1,663 @@
<?php
class DashboardsModel{
/**
* get all gadgets by user type (used for creating new dashboards)
* @param INT $idDashboard id of the dashborad
* @param INT $selectedUserType id of the user type that was selected
* @return array gadgets array
*/
public function getAllGadgets($idDashboard, $selectedUserType){
global $database, $user;
$idDashboard = $database->escapeValue($idDashboard);
$idUserType = ($user->getUserType() === USER_TYPES['BROKER'] && intval($selectedUserType) !== 0)
? $selectedUserType
: $user->getIdUserType();
$sql = "SELECT g.id AS idGadget,
g.name,
g.module,
CASE WHEN rdg.idGadget IS NULL THEN 0 ELSE 1 END AS isSelected
FROM ".TABLES['gadgets']." g
INNER JOIN ".TABLES['rel_user_types_gadgets']." rutg
ON rutg.idGadget=g.id
LEFT OUTER JOIN ".TABLES['rel_dashboard_gadgets']." rdg
ON rdg.idGadget=g.id AND rdg.idDashboard=$idDashboard
WHERE rutg.idUserType=".$idUserType."
ORDER BY g.name";
return $database->fetchResultArray($sql);
}
/**
* get info for a dashbord on edit
* @param INT $idDashboard id of the dashborad
* @return HASHARRAY dashborad info
*/
public function getDashboardInfo($idDashboard){
global $database, $user;
$data = [];
$whereSql = $user->getUserType() === USER_TYPES['BROKER']
? "AND (d.idUser=".$user->getUserId()." OR d.visibility='public')"
: "AND (d.idUser=".$user->getUserId().")";
$idDashboard = intval($database->escapeValue($idDashboard));
$sql = "SELECT
d.id AS idDashboard,
d.name,
d.visibility,
d.idUserType
FROM ".TABLES['dashboards']." d
WHERE d.id=$idDashboard $whereSql";
$info = $database->fetchResultArray($sql);
if(empty($info)){
return [
'messages' => [
'code' => 'error',
'message' => 'NOT_OWNER_OF_DASHBAORD'
]];
}
$data['dashboardInfo'] = $info[0];
return $data;
}
/**
* 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 all dashborads for a user (including public ones)
* @return ARRAY array with all dashborads
*/
public function getUserDashboards(){
global $database, $user;
$data = [];
$extraFields = '';
$whereSql = $user->getUserType() === USER_TYPES['BROKER']
? ""
: "AND d.idUserType=".$user->getIdUserType();
$sql = "SELECT d.id AS idDashboard,
d.name,
d.visibility,
ut.type
FROM ".TABLES['dashboards']." d
INNER JOIN ".TABLES['user_types']." ut
ON ut.id=d.idUserType
WHERE d.idUser=".$user->getUserId()." OR (d.visibility='public' $whereSql)
ORDER BY d.idUserType, d.lastUpdated DESC";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['type']][] = $row;
}
return $data;
}
/**
* 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;
}
/**
* generate a filter condition on gadget filter
* @param Array $filters array of filters
* @return string sql filter condtion
*/
private function setFilterSql($filters){
$whereSql = "1=1";
if(!empty($filters)){
foreach ($filters as $key => $filterValue) {
$whereSql .= " AND $key like '%$filterValue%'";
}
}
return $whereSql;
}
private function setOrderBySql($sortBy){
$orderBySql = "";
if( isset($sortBy->key) && isset($sortBy->direction) ){
$orderBySql .= $sortBy->key." ".$sortBy->direction;
}
return $orderBySql;
}
/**
* get information for the order central gadget
* @param Array $filters array of filters to be applied
* @return Array array with orders info
*/
public function getOrderCentralInfo($filters, $sortBy){
global $database, $user;
$filters = json_decode($filters);
$sortBy = json_decode($sortBy);
$whereSql = $this->setFilterSql($filters);
$orderBySql = $this->setOrderBySql($sortBy);
$extraJoin = '';
$extraWhere = '';
if(!$orderBySql){
$orderBySql = "orderDate DESC";
}
if($user->getUserType() === USER_TYPES['BROKER']) {
$extraWhere = "AND (
b.idUser = ".$user->getUserId()."
OR o.assignedTo IS NULL
)";
}
if($user->getUserType() === 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
AND c.idUser = ".$user->getUserId();
}
if($user->getUserType() === 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
AND cl.idUser = ".$user->getUserId();
}
if($user->getUserType() === 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=".$user->getUserId();
}
$sql = "SELECT * FROM(
SELECT o.id AS idOrder,
o.orderNumber,
o.orderDate,
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";
return $database->fetchResultArray($sql);
}
/**
* get information for the assigned orders gadget
* @param Array $filters array of filters to be applied
* @param Array $sortBy array of element to apply the sorting
* @return Array array with orders info
*/
public function getAssignedOrdersInfo($filters, $sortBy){
global $database, $user;
$filters = json_decode($filters);
$sortBy = json_decode($sortBy);
$whereSql = $this->setFilterSql($filters);
$orderBySql = $this->setOrderBySql($sortBy);
if(!$orderBySql){
$orderBySql = "orderDate DESC";
}
$sql = "SELECT * FROM(
SELECT o.id AS idOrder,
o.orderNumber,
o.orderDate,
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
LEFT JOIN ".TABLES['brokers']." b
ON o.assignedTo = b.id
WHERE o.status!='production' AND o.status!='canceled' AND o.status!='end-of-life'
AND b.idUser != ".$user->getUserId()."
AND o.assignedTo IS NOT NULL
GROUP BY o.id
) orders
WHERE $whereSql
ORDER BY $orderBySql
LIMIT 5";
return $database->fetchResultArray($sql);
}
/**
* 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 = $this->setFilterSql($filters);
$orderBySql = $this->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,
rops.idPackage,
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 AND rod.idPackage=tna.idPackage
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 AND rop.idPackage=tna.idPackage
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 AND rosd.idPackage=tna.idPackage
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;
}
/**
* validate data for creating / editing a dashborad
* @param INT $idDashboard id for the dashborad (used only for edit)
* @param String $name name for the deshborad
* @param String $visibility visibility of dashboard (can be public or private)
* @param Array $gadgets array of gadgets for dashborad
* @param INT $selectedUserType id of the user type for witch the gadget is created / edited
* @return Array validation error message or null in case of valid data
*/
private function validateDashboardData($idDashboard, $name, $visibility, $gadgets, $selectedUserType){
global $database, $user;
$data = [];
if(empty($gadgets)){
$data['messages'][] =[
'code' => 'error',
'message' => 'NO_GADGETS'
];
return $data;
}
$idDashboard = $database->escapeValue($idDashboard);
$name = $database->escapeValue($name);
$visibility = $database->escapeValue($visibility);
$selectedUserType = $database->escapeValue($selectedUserType);
if($idDashboard === 'null'){
$sql = "SELECT d.id
FROM ".TABLES['dashboards']." d
WHERE name='$name' AND idUser=".$user->getUserId(). "
LIMIT 1";
$query = $database->query($sql);
if($database->numRows($query) > 0){
$data['messages'][] =[
'code' => 'error',
'message' => 'NAME_ALREADY_EXISTS'
];
return $data;
}
}
if($visibility !== 'private' && $visibility !== 'public'){
$data['messages'][] =[
'code' => 'error',
'message' => 'INVALID_VISIBILITY'
];
}
$checkMessage = $database->isEmpty('NAME', $name);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
$checkMessage = $database->invalidLength('NAME', $name, 60);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
if($visibility === 'public'){
$checkMessage = $database->isEmpty('UserType', $selectedUserType);
if($checkMessage){
$data['messages'][] = $checkMessage;
}
}
return $data;
}
/**
* insert or update the gadgets for a dashborad
* @param INT $idDashboard id of the dashboard
* @param Array $gadgets array of gadgets
* @return INT number of affected rows
*/
private function insertUpdateGadgets($idDashboard, $gadgets){
global $database;
$newIds = "";
$sql = "INSERT IGNORE INTO ".TABLES['rel_dashboard_gadgets']."
(idDashboard, idGadget, position)
VALUES";
foreach ($gadgets as $gadget) {
$gadget->idGadget = $database->escapeValue($gadget->idGadget);
$gadget->position = $database->escapeValue($gadget->position);
$sql .= "($idDashboard, $gadget->idGadget, $gadget->position),";
$newIds .= $gadget->idGadget.",";
}
$newIds = rtrim($newIds, ',');
$sql = rtrim($sql, ',');
$query = $database->query($sql);
$modified = $database->affectedRows();
$sql = "DELETE FROM ".TABLES['rel_dashboard_gadgets']."
WHERE idDashboard=$idDashboard AND idGadget NOT IN($newIds)";
$query = $database->query($sql);
$modified += $database->affectedRows();
return $modified;
}
/**
* create or edit a dashborad
* @param INT $idDashboard id of the dashborad(used only for edit)
* @param String $name name for the dashbroad
* @param String $visibility visibility of dashboard (can be public or private)
* @param Array $gadgets array of gadgets for dashborad
* @param INT $selectedUserType id of the user type for witch the gadget is created / edited
* @return Array update message
*/
public function createDashboard($idDashboard, $name, $visibility, $gadgets, $selectedUserType){
global $database, $user;
$data = [];
$gadgets = json_decode($gadgets);
$idUserType = $user->getIdUserType();
$idUser = $user->getUserId();
if($visibility === 'public'){
$selectedUserType = ($user->getUserType() === USER_TYPES['BROKER'] && $selectedUserType !== 0) ? $selectedUserType : $idUserType;
$idUser = 'null';
}else{
$selectedUserType = $idUserType;
}
if(intval($idDashboard) !== 0){
$whereSql = $user->getUserType() !== USER_TYPES['BROKER']
? " AND d.idUser=".$user->getUserId()
: " AND (d.visibility='public' OR d.idUser=".$user->getUserId().")";
$sql = "SELECT
d.id AS idDashboard
FROM ".TABLES['dashboards']." d
WHERE d.id=$idDashboard $whereSql
LIMIT 1";
$query = $database->query($sql);
$isMyDashboard = $database->numRows($query) > 0 ? true : false;
if(!$isMyDashboard){
$data['messages'][] =[
'code' => 'error',
'message' => 'NOT_OWNER_OF_DASHBAORD'
];
return $data;
}
}else{
$idDashboard = 'null';
}
$data = $this->validateDashboardData($idDashboard, $name, $visibility, $gadgets, $selectedUserType);
if(!empty($data)){
return $data;
}
$sql = "INSERT INTO ".TABLES['dashboards']."
(id, idUser, idUserType, name, visibility)
VALUES($idDashboard,".$idUser.",'$selectedUserType','$name', '$visibility')
ON DUPLICATE KEY UPDATE
name=VALUES(name),
idUserType=VALUES(idUserType),
visibility=VALUES(visibility)";
$query = $database->query($sql);
$idDashboard = $idDashboard == 'null' ? $database->getInsertId() : $idDashboard;
$insertGadgetsMessage = $this->insertUpdateGadgets($idDashboard, $gadgets);
if(intval($idDashboard) !== 0){
$data['messages'][] =[
'code' => 'success',
'message' => 'DASHBORAD_UPDATED'
];
}else{
$data['messages'][] =[
'code' => 'success',
'message' => 'DASHBORAD_CREATED'
];
}
return $data;
}
/**
* get user types in the system
* @return Array array with user types
*/
public function getUserTypes(){
global $database, $user;
if($user->getUserType() !== USER_TYPES['BROKER']){
return [];
}
$sql = "SELECT ut.id,
ut.type
FROM ".TABLES['user_types']." ut";
return $database->fetchResultArray($sql);
}
/**
* remove a dashborad
* @param INT $idDashboard id of the dashborad
* @return Array update message
*/
public function removeDashboard($idDashboard){
global $database, $user;
$idDashboard = $database->escapeValue($idDashboard);
$data = [];
$whereSql = $user->getUserType() === USER_TYPES['BROKER']
? "AND (d.idUser=".$user->getUserId()." OR d.visibility='public')"
: "AND (d.idUser=".$user->getUserId().")";
$idDashboard = intval($database->escapeValue($idDashboard));
$sql = "SELECT
d.id AS idDashboard
FROM ".TABLES['dashboards']." d
WHERE d.id=$idDashboard $whereSql";
$info = $database->fetchResultArray($sql);
if(empty($info)){
$data['messages'][] = [
'code' => 'error',
'message' => 'NOT_OWNER_OF_DASHBAORD'
];
return $data;
}
$sql = "DELETE FROM ".TABLES['dashboards']."
WHERE id=$idDashboard";
$query = $database->query($sql);
if($database->affectedRows() > 0 ){
$data['messages'][] = [
'code' => 'success',
'message' => 'DASHBORAD_REMOVED'
];
return $data;
}
$data['messages'][] =[
'code' => 'error',
'message' => 'DASHBORAD_REMOVE_ERROR'
];
return $data;
}
}
?>

View File

@@ -0,0 +1,14 @@
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/dashboards.directive.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/dashboards-view.directive.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/dashboards-filters.service.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/dashboards-filters.directive.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/create-dashboard.directive.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/gadget-order-central.directive.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/gadget-assigned-orders.directive.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dashboards/gadget-next-actions.directive.js';?>" type="text/javascript"></script>
<div id="dashboards" class="container-fluid col-md-12">
<h1>{{ 'dashboards.TITLE' | translate }}</h1>
<dashboards ng-controller="dashboardsCtrl"></dashboards>
</div>

View File

@@ -0,0 +1,77 @@
<div id="create-dashboard-container" class="row">
<div class="create-box col-md-12">
<input type="text" placeholder="{{ 'dashboards.headers.DASHBOARD_NAME' | translate }}" ng-model="dashboardName" class="dashborad-input col-md-2" />
<?php
if($user->getUserType() === USER_TYPES['BROKER']){
require_once('PublicPrivateDashboard.php');
}
?>
</div>
<div ng-if="!viewGadgets" class="dashborad-gadgets">
<div class="gadget-layer col-md-6" ng-repeat="gadget in selectedGadgets">
<div class="gadget">
<h3 class="col-md-12">{{gadget.name}}</h3>
<div class="drop-zone"
data-drop="true"
jqyoui-droppable="{onDrop:'gadgetDropped(gadget)'}">
{{ 'dashboards.buttons.DROP' | translate }}
</div>
<div id="selected-gadget-{{gadget.idGadget}}"
class="drag-gadget"
idGadget="{{gadget.idGadget}}"
data-drag="true"
jqyoui-draggable="{animate:true, onStart:'gadgetDragStart()', onStop:'gadgetDragStop()', scroll: false}"
data-jqyoui-options="{revert: true}">
<span class="glyphicon glyphicon-move"></span>
{{ 'dashboards.buttons.DRAG' | translate }}
</div>
<div class="remove-gadget btn btn-danger" ng-click="removeGadget(gadget)">
<span class="remove-gadget-icon glyphicon glyphicon-minus"></span>
{{ 'dashboards.buttons.REMOVE_GADGET' | translate }}
</div>
</div>
</div>
<div class="gadget-layer col-md-6">
<div class="gadget">
<div class="add-gadget" ng-click="showHideGadgets()">
<span class="add-gadget-icon glyphicon glyphicon-plus"></span>
{{ 'dashboards.buttons.ADD_GADGET' | translate }}
</div>
</div>
</div>
</div>
<div ng-if="viewGadgets" class="slect-gadgets">
<div class="col-md-4" ng-repeat="gadget in gadgets">
<div class="gadget">
<h3 class="col-md-12">{{gadget.name}}</h3>
<div class="gadget-description col-md-8">
{{ 'dashboards.gadgets.' + gadget.module + '.DESCRIPTION' | translate }}
</div>
<div class="col-md-4">
<div ng-if="!gadget.isSelected" class="btn btn-primary" ng-click="addGadget(gadget)">
<span class="glyphicon glyphicon-plus"></span>
{{ 'dashboards.buttons.ADD_TO_DASHBOARD' | translate }}
</div>
<div ng-if="gadget.isSelected" class="alert alert-success">
{{ 'dashboards.messages.GADGET_ALREADY_IN_DASHBOARD' | translate }}
</div>
</div>
</div>
</div>
</div>
<div class="create-box col-md-12">
<div ng-if="!viewGadgets" class="btn btn-primary" ng-click="createDashboard()">
<span class="glyphicon glyphicon-plus"></span>
{{ 'dashboards.buttons.' + getButtonTranslationKey() | translate }}
</div>
<div ng-if="viewGadgets" class="btn btn-danger" ng-click="showHideGadgets()">
<span class="glyphicon glyphicon-chevron-left"></span>
{{ 'dashboards.buttons.BACK' | translate }}
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
<div class="fitler-layer">
<div class="filter-title">
{{ 'dashboards.headers.FILTER_COLUMN' | translate }}<br/>
</div>
<div ng-if="isFilterSet()" class="filter-message alert alert-success">
<span class="glyphicon glyphicon-info-sign"></span>
<span class="filter-title">{{ 'dashboards.headers.APPLIERD_FILTER' | translate }}</span> {{getFilterText(gadget.module)}}
</div>
<div class="filter-logic">
{{filterKey()}}:
<input type="text"
filterType="textValue"
class="filter-input"
ng-model="filters[filterKey()]"/>
</div>
<div ng-click="applyFilter(gadget.module)" class="filter-apply btn btn-primary">
<span class="glyphicon glyphicon-search"></span> {{ 'dashboards.buttons.APPLY_FILTER' | translate }}
</div>
<div ng-click="clearFilter(gadget.module)" class="filter-clear btn btn-danger">
<span class="glyphicon glyphicon-remove"></span> {{ 'dashboards.buttons.CLEAR_FILTER' | translate }}
</div>
</div>

View File

@@ -0,0 +1,38 @@
<button type="button"
id="dashboardsViewBtn"
subModule="dashborardsView"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'dashboards.buttons.VIEW_DASHBOARD' | translate }}</button>
<button type="button"
id="dashboardsCreateBtn"
subModule="dashboardsCreate"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'dashboards.buttons.CREATE_DASHBOARD' | translate }}</button>
<div class="row">
<div class="col-md-12"
id="dashboards-layer"
ng-if="isSubmoduleVisible('dashborardsView')"
ng-init="getDashborad()">
<dashboards-view ng-controller="dashboardsViewCtrl" ng-init="initMyDashborad()"></dashboards-view>
</div>
</div>
<div class="row">
<div class="col-md-12"
id="dashboards-create-layer"
ng-if="isSubmoduleVisible('dashboardsCreate')">
<h3>{{ 'dashboards.headers.' + getHeaderKey('create') | translate }}</h3>
<create-dashboard ng-controller="createDashboardCtrl" ng-init="initCreate()"></create-dashboard>
</div>
</div>
<div class="row">
<div class="col-md-12"
id="dashboards-edit-layer"
ng-if="isSubmoduleVisible('dashboardsEdit')">
<h3>{{ 'dashboards.headers.' + getHeaderKey('edit') | translate }}</h3>
<create-dashboard ng-controller="createDashboardCtrl" ng-init="initCreate()"></create-dashboard>
</div>
</div>

View File

@@ -0,0 +1,42 @@
<div class="dashboard-name col-md-12">
<div class="col-md-12">
<span class="dashborad-selected-name">{{dashboardInfo.name}}</span>
<span class="owner-btns" ng-if="dashboardInfo.isOwner">
<a href="dashboards?subModule=dashboardsEdit&idDashboard={{dashboardInfo.idDashboard}}">
<span class="edit-dashboard-btn glyphicon glyphicon-pencil"></span>
</a>
<span class="remove-dashborad-btn glyphicon glyphicon-remove" ng-click="showHideRemoveDialog()"></span>
</span>
<span class="select-dashboard-btn glyphicon glyphicon-menu-hamburger" ng-click="showSelectDashborad()"></span>
</div>
<div class="select-dashboard-layer col-md-3" ng-if="isSelectDashboardVisible">
<h3 class="select-dashboard-title">{{ 'dashboards.headers.SELECT_DASHBOARD' | translate }}</h3>
<div class="select-dashborad-group" ng-repeat="(dashboradType, dashborads) in allDashboards">
<div class="select-dashboard-type">{{dashboradType}}</div>
<div class="dashboard-row" ng-repeat="dashboard in dashborads" ng-click="getMyDashboard(dashboard.idDashboard)">
{{dashboard.name}}
<span class="{{dashboard.visibility}} visibility-icon glyphicon glyphicon-eye-{{getDashboradIcon(dashboard.visibility)}}"></span>
</div>
</div>
</div>
<div id="dialog-confirm"
dialog
ng-if="isRemoveDialogVisible"
on-confirmation="removeDashboard"
on-close="showHideRemoveDialog"
is-modal="true"
has-buttons="true"
parameters="dashboardInfo.idDashboard"
title="{{'dashboards.headers.REMOVE_DASHBOARD' | translate}}">
<p><span class="glyphicon glyphicon-warning-sign"></span>{{'dashboards.messages.REMOVE_DASHBORAD_CONFIRMATION' | translate}} <b>{{dashboardInfo.name}}</b>?</p>
</div>
</div>
<div id="dashboard-gadgets-container" class="row">
<div
class="gadget-layer col-md-6"
ng-repeat="gadget in gadgets">
<div class="gadget col-md-12" id="dashboard-gadget-{{gadget.idGadget}}" ng-init="gadgetsDirective(gadget)"></div>
</div>
</div>

View File

@@ -0,0 +1,10 @@
<div ng-if="canChangeVisibility()" class="col-md-1 visibility-layer {{visibility.value}}" ng-click="changeVisibility()">
<span class="visibility-icon glyphicon glyphicon-eye-{{visibility.icon}}"></span>
<span class="visibility-message">{{visibility.value}}</span>
</div>
<div class="user-type-select-layer col-md-2" ng-if="isPublic()">
{{ 'dashboards.headers.FOR' | translate }}
<select ng-change="getGadgets()" class="user-type-select" ng-model="$parent.selectedUserType">
<option ng-repeat="option in userTypes" value="{{option.id}}">{{option.type}}</option>
</select>
</div>

View File

@@ -0,0 +1,65 @@
<div ng-controller="gadgetAssignedOrdersCtrl" ng-init="getAssignedOrdersInfo()" class="order-central-orders">
<h3>
{{ 'dashboards.headers.ASSIGNED_ORDERS' | translate }}
<span ng-if="filterService.isFilterSet(gadget.module)" class="is-fitlered glyphicon glyphicon-filter"></span>
</h3>
<dashboards-filters
ng-if="filterService.isFilterVisible(gadget.module)"
ng-init="setFilterParams(gadget.module)"
ng-controller="dashboardsFiltersCtrl">
</dashboards-filters>
<div class="gadget-row col-md-12">
<div class="gadget-row-column gadget-header col-md-2">
{{ 'dashboards.headers.ORDER' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'orderNumber', 'textFilter')"
class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'orderNumber')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'orderNumber')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-3">
{{ 'dashboards.headers.ASSIGNED_TO' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'assignedTo', 'textFilter')"
class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'assignedTo')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'assignedTo')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-3">
{{ 'dashboards.headers.ORDER_DATE' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'orderDate', 'dateFilter')" class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'orderDate')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'orderDate')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-2">
{{ 'dashboards.headers.TOTAL' | translate }}
<span ng-click="filterService.sortBy(gadget.module, 'fixedPrice')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'fixedPrice')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-2">
{{ 'dashboards.headers.STATUS' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'status', 'textFilter')" class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'status')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'status')}}"></span>
</div>
</div>
<div class="gadget-row col-md-12" ng-repeat="order in orders">
<div class="gadget-row-column col-md-2">
<a href="orders?subModule=orders_steps&idOrder={{order.idOrder}}&orderNumber={{order.orderNumber}}">{{order.orderNumber}}</a>
</div>
<div class="gadget-row-column col-md-3">
{{order.assignedTo}}
</div>
<div class="gadget-row-column col-md-3">
{{order.orderDate}}
</div>
<div class="gadget-row-column col-md-2">
{{order.fixedPrice}}
<div ng-if="order.recurringPrice > 0">
({{ 'dashboards.headers.RECURRING' | translate }} {{order.recurringPrice}})
</div>
</div>
<div class="order-status-{{order.status}} gadget-row-column col-md-2">
{{order.status}} <span class="{{getStatusIcon(order.status)}}"></span>
</div>
</div>
</div>

View File

@@ -0,0 +1,41 @@
<div ng-controller="gadgetNextActionsCtrl" class="next-actions">
<h3>
{{ 'dashboards.headers.NEXT_ACTIONS' | translate }}
<span ng-if="filterService.isFilterSet(gadget.module)" class="is-fitlered glyphicon glyphicon-filter"></span>
</h3>
<dashboards-filters
ng-if="filterService.isFilterVisible(gadget.module)"
ng-init="setFilterParams(gadget.module)"
ng-controller="dashboardsFiltersCtrl">
</dashboards-filters>
<div class="gadget-row col-md-12">
<div class="gadget-row-column gadget-header col-md-2">
{{ 'dashboards.headers.ORDER' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'orderNumber', 'textFilter')" class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'orderNumber')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'orderNumber')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-4">
{{ 'dashboards.headers.ACTION' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'stepAction', 'textFilter')" class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'stepAction')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'stepAction')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-3">
{{ 'dashboards.headers.STATUS' | translate }}
</div>
</div>
<div class="gadget-row col-md-12" ng-repeat="action in actions">
<div class="gadget-row-column col-md-2">
<a href="orders?subModule=orders_steps&idOrder={{action.idOrder}}&orderNumber={{action.orderNumber}}">{{action.orderNumber}}</a>
</div>
<div class="gadget-row-column col-md-4">
{{action.stepAction}}
</div>
<div class="gadget-row-column col-md-4">
<span class="action-status {{action.status}}">{{action.status}}</span>
</div>
</div>
</div>

View File

@@ -0,0 +1,65 @@
<div ng-controller="gadgetOrderCentralCtrl" ng-init="getOrderCentralInfo()" class="order-central-orders">
<h3>
{{ 'dashboards.headers.ORDER_CENTRAL' | translate }}
<span ng-if="filterService.isFilterSet(gadget.module)" class="is-fitlered glyphicon glyphicon-filter"></span>
</h3>
<dashboards-filters
ng-if="filterService.isFilterVisible(gadget.module)"
ng-init="setFilterParams(gadget.module)"
ng-controller="dashboardsFiltersCtrl">
</dashboards-filters>
<div class="gadget-row col-md-12">
<div class="gadget-row-column gadget-header col-md-2">
{{ 'dashboards.headers.ORDER' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'orderNumber', 'textFilter')"
class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'orderNumber')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'orderNumber')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-3">
{{ 'dashboards.headers.ASSIGNED_TO' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'assignedTo', 'textFilter')"
class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'assignedTo')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'assignedTo')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-3">
{{ 'dashboards.headers.ORDER_DATE' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'orderDate', 'dateFilter')" class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'orderDate')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'orderDate')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-2">
{{ 'dashboards.headers.TOTAL' | translate }}
<span ng-click="filterService.sortBy(gadget.module, 'fixedPrice')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'fixedPrice')}}"></span>
</div>
<div class="gadget-row-column gadget-header col-md-2">
{{ 'dashboards.headers.STATUS' | translate }}
<span ng-click="filterService.showFilter(gadget.module, 'status', 'textFilter')" class="filter-value glyphicon glyphicon-filter"></span>
<span ng-click="filterService.sortBy(gadget.module, 'status')"
class="sort-icon sort glyphicon {{filterService.getSortIcon(gadget.module, 'status')}}"></span>
</div>
</div>
<div class="gadget-row col-md-12" ng-repeat="order in orders">
<div class="gadget-row-column col-md-2">
<a href="orders?subModule=orders_steps&idOrder={{order.idOrder}}&orderNumber={{order.orderNumber}}">{{order.orderNumber}}</a>
</div>
<div class="gadget-row-column col-md-3">
{{order.assignedTo}}
</div>
<div class="gadget-row-column col-md-3">
{{order.orderDate}}
</div>
<div class="gadget-row-column col-md-2">
{{order.fixedPrice}}
<div ng-if="order.recurringPrice > 0">
({{ 'dashboards.headers.RECURRING' | translate }} {{order.recurringPrice}})
</div>
</div>
<div class="order-status-{{order.status}} gadget-row-column col-md-2">
{{order.status}} <span class="{{getStatusIcon(order.status)}}"></span>
</div>
</div>
</div>

View File

@@ -0,0 +1,100 @@
<?php
/**
* ShopController controlls the actions for docuemnts
*/
class DocumentsController{
private $model;
function __construct(){
$this->model = new DocumentsModel();
}
/**
* get documents for documents view
* @return json list of documents
*/
public function getDocuments(){
$idDocument = isset($_REQUEST['idDocument']) ? $_REQUEST['idDocument'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->getDocuments($idDocument, $idPackage));
}
/**
* get documents and apckages for linking
* @return json a list for documetns and one for packages
*/
public function getDocumentsAndPackages(){
echo json_encode($this->model->getDocumentsAndPackages());
}
/**
* update linking between a package and docuemtns
* @return json update message
*/
public function updatePackageDocuments(){
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$documents = isset($_REQUEST['documents']) ? $_REQUEST['documents'] : '[]';
echo json_encode($this->model->updatePackageDocuments($idPackage, $documents));
}
/**
* get documents types
* @return json a list for document types
*/
public function getDocumentTypes(){
echo json_encode($this->model->getDocumentTypes());
}
public function uploadNewDocument(){
$idDocumentType = isset($_REQUEST['idDocumentType']) ? $_REQUEST['idDocumentType'] : 0;
$documentName = isset($_REQUEST['documentName']) ? $_REQUEST['documentName'] : '';
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
echo json_encode($this->model->uploadNewDocument($idDocumentType, $documentName, $file));
}
public function addNewDocumnetType(){
$documentNewType = isset($_REQUEST['documentNewType']) ? $_REQUEST['documentNewType'] : '';
echo json_encode($this->model->addNewDocumnetType($documentNewType));
}
public function removeDocument(){
$idDocument = isset($_REQUEST['idDocument']) ? $_REQUEST['idDocument'] : 0;
echo json_encode($this->model->removeDocument($idDocument));
}
/**
* include decouments template
*/
public function documentsTemplate(){
global $user;
require_once('templates/DocumentsTemplate.php');
}
/**
* include decouments view template
*/
public function documentsViewTemplate(){
require_once('templates/DocumentsViewTemplate.php');
}
/**
* include decouments view template
*/
public function documentsLinkTemplate(){
require_once('templates/DocumentsLinkTemplate.php');
}
/**
* include decouments view template
*/
public function DocumentsAddTemplate(){
require_once('templates/DocumentsAddTemplate.php');
}
/**
* open documents page
*/
public function showPage(){
require_once('DocumentsPage.php');
}
}

View File

@@ -0,0 +1,332 @@
<?php
/**
* Data manipulation for the docuemnts
*/
class DocumentsModel{
private $specialDocumentTypes = [2, 3, 5, 7, 10];
//orderQuestionaire, configuration, customerAcceptance, OrderAgreement, installationProtocol
/**
* get linked packages to a documnet
* @param INT $idDocument id of the document
* @return HashArray Array of packages for each document
*/
private function getLinkedPackages($idDocument = 0){
global $database;
$data = [];
$whereSql = '';
if(intval($idDocument) !== 0){
$whereSql = " AND d.id=$idDocument";
}
$sql = "SELECT d.id AS idDocument,
p.name AS packageName
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['rel_package_documents']." rpd
ON rpd.idDocument=d.id
INNER JOIN ".TABLES['packages']." p
ON p.id=rpd.idPackage
WHERE d.uploadedBy IS NULL $whereSql";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idDocument']][] = $row;
}
return $data;
}
/**
* get documents for view documetns
* @param INT $idDocument id for the doceument
* @param INT $idPackage id for the pacakge
* @return Array array of documents
*/
public function getDocuments($idDocument, $idPackage){
global $database;
$data = [];
$whereSql = '';
$extraJoin = '';
$idDocument = $database->escapeValue($idDocument);
$idPackage = $database->escapeValue($idPackage);
if(intval($idDocument) !== 0){
$whereSql = " AND d.id=$idDocument";
}
if(intval($idPackage) !== 0){
$extraJoin = " INNER JOIN ".TABLES['rel_package_documents']." rpd
ON rpd.idDocument=d.id AND rpd.idPackage=$idPackage";
}
$linkedPackages = $this->getLinkedPackages($idDocument, $idPackage);
$specialDocumentTypesSql = implode(',', $this->specialDocumentTypes);
$sql = "SELECT d.id AS idDocument,
d.documentName,
d.documentPath,
dt.type AS documentType,
d.extension
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['document_types']." dt
ON dt.id=d.idDocumentType
$extraJoin
WHERE dt.id NOT IN($specialDocumentTypesSql) $whereSql
ORDER BY documentType, documentName";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
if(isset($linkedPackages[$row['idDocument']])){
$row['packages'] = $linkedPackages[$row['idDocument']];
}
$data[$row['documentType']][] = $row;
}
return $data;
}
/**
* get packages to link to the documents
* @return HashArray array of packages
*/
public function getPackages(){
global $database;
$data = [];
$specialDocumentTypesSql = implode(',', $this->specialDocumentTypes);
$sql = "SELECT p.id AS idPackage,
p.name AS packageName,
c.code AS countryCode,
docs.idDocument,
docs.documentName,
docs.extension,
docs.documentType
FROM ".TABLES['packages']." p
INNER JOIN ".TABLES['countries']." c
ON c.id=p.idCountry
LEFT OUTER JOIN
(
SELECT
rpd.idPackage,
rpd.idDocument,
d.documentName,
d.extension,
dt.type AS documentType
FROM ".TABLES['rel_package_documents']." rpd
INNER JOIN ".TABLES['documents']." d
ON rpd.idDocument=d.id
INNER JOIN ".TABLES['document_types']." dt
ON dt.id=d.idDocumentType
WHERE dt.id NOT IN($specialDocumentTypesSql)
) docs
ON p.id=docs.idPackage
ORDER BY documentType, documentName";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$idPackage = $row['idPackage'];
$packageDetails[$idPackage]['idPackage'] = $idPackage;
$packageDetails[$idPackage]['packageName'] = $row['packageName'];
$packageDetails[$idPackage]['countryCode'] = $row['countryCode'];
unset($row['idPackage']);
unset($row['packageName']);
unset($row['countryCode']);
if(!isset($packageDetails[$idPackage]['documents'])){
$packageDetails[$idPackage]['documents'] = [];
}
if($row['idDocument']){
$packageDetails[$idPackage]['documents'][] = $row;
}
}
foreach($packageDetails as $details) {
$data[] = $details;
}
usort($data, array($this, "comparePackNames"));
return $data;
}
/**
* compare package names and sort them
* @param Array $a first array from all packages with details
* @param Array $b second array from all packages with details
* @return Int < 0 if a is less than b; > 0 if a is greater than b, and 0 if they are equal
*/
private function comparePackNames($a, $b) {
return strcmp($a['packageName'], $b['packageName']);
}
/**
* get documents and packages for link documents view
* @return HashArray array containg the documents and the packages
*/
public function getDocumentsAndPackages(){
global $database;
$data = [];
$specialDocumentTypesSql = implode(',', $this->specialDocumentTypes);
$sql = "SELECT d.id AS idDocument,
d.documentName,
d.extension,
dt.type AS documentType
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['document_types']." dt
ON d.idDocumentType=dt.id
WHERE dt.id NOT IN ($specialDocumentTypesSql)
ORDER BY documentType, d.documentName";
$data['documents'] = $database->fetchResultArray($sql);
$data['packages'] = $this->getPackages();
return $data;
}
public function updatePackageDocuments($idPackage, $documents){
global $database;
$data = [];
$idPackage = $database->escapeValue($idPackage);
$documents = json_decode($documents);
if(intval($idPackage) == 0){
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_PACKAGE'
];
}
$sql = "";
$idsToNotDelete = "AND idDocument NOT IN(";
foreach ($documents as $document) {
$document->idDocument = $database->escapeValue($document->idDocument);
$sql .= "($idPackage, ".$document->idDocument."),";
$idsToNotDelete .= $document->idDocument.",";
}
$sql = rtrim($sql, ',');
$idsToNotDelete = rtrim($idsToNotDelete, ','). ')';
if(!empty($sql)){
$sql = "INSERT IGNORE INTO ".TABLES['rel_package_documents']."
(idPackage, idDocument)
VALUES $sql";
$query = $database->query($sql);
$inserted = $database->affectedRows();
}else{
$inserted = 0;
$idsToNotDelete = "";
}
$sqlDel ="DELETE FROM ".TABLES['rel_package_documents']."
WHERE idPackage=$idPackage $idsToNotDelete";
$query = $database->query($sqlDel);
$deleted = $database->affectedRows();
if($inserted > 0 || $deleted >0){
$data['messages'][] = [
'code' => 'success',
'message' => 'DOCUMENTS_LINKED_TO_PACKAGE'
];
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}
return $data;
}
public function getDocumentTypes(){
global $database;
$data = [];
$sql = "SELECT dt.id AS idDocumentType,
dt.type,
dt.isSpecialType
FROM ".TABLES['document_types']." dt
ORDER BY dt.type ASC";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[] = $row;
}
return $data;
}
public function uploadNewDocument($idDocumentType, $documentName, $file){
global $database;
$idDocumentType = $database->escapeValue($idDocumentType);
$documentName = $database->escapeValue($documentName);
if(!$documentName){
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_NAME'
];
return $data;
}
if(!$idDocumentType){
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_TYPE'
];
return $data;
}
$specialDocTypes = implode(',', $this->specialDocumentTypes);
$sql = "SELECT d.id
FROM ".TABLES['documents']." d
WHERE d.documentName='$documentName' AND d.id NOT IN($specialDocTypes)";
$query = $database->query($sql);
if($database->numRows($query) > 0){
$data['messages'][] = [
'code' => 'error',
'message' => 'NAME_EXISTS'
];
return $data;
}
$fileManager = new FileManager();
$data = $fileManager->uploadFile($file, $idDocumentType, $documentName);
if(isset($data['messages'])){
return $data;
}
$data['messages'][] = [
'code' => 'success',
'message' => 'DOCUMENT_UPLOADED'
];
return $data;
}
public function addNewDocumnetType($documentNewType){
$fileManager = new FileManager();
return $fileManager->addNewDocumnetType($documentNewType);
}
public function removeDocument($idDocument){
global $database;
$fileManager = new FileManager();
$data = $fileManager->removeDocument($idDocument);
foreach ($data['messages'] as $messageObj) {
if ($messageObj['code'] === 'success') {
$sqlUnlink = "
DELETE
FROM ".TABLES['rel_package_documents']."
WHERE idDocument=$idDocument";
$query = $database->query($sqlUnlink);
}
}
return $data;
}
}

View File

@@ -0,0 +1,9 @@
<script src="<?php echo PATH_JS_COMPONENTS.'documents/documents.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'documents/documents-view.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'documents/documents-link.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'documents/documents-add.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<div id="documents-module" class="container-fluid col-md-12">
<h1>{{ 'documents.TITLE' | translate }}</h1>
<documents ng-controller="documentsCtrl"></documents>
</div>

View File

@@ -0,0 +1,5 @@
<button type="button"
id="documents-add"
subModule="documentsAdd"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'documents.buttons.ADD_DOCUMENTS' | translate }}</button>

View File

@@ -0,0 +1,7 @@
<div class="row">
<div class="col-md-12"
id="documents-add-layer"
ng-if="isSubmoduleVisible('documentsAdd')">
<documents-add ng-controller="documentsAddCtrl" ng-init="getDocumentTypes()"></documents-add>
</div>
</div>

View File

@@ -0,0 +1,56 @@
<div class="documents-add-layer row">
<div class="col-md-3">
<div class="documetns-types">
<div class="documents-header">
{{'documents.headers.DOCUMENT_TYPES' | translate}}
</div>
<div class="document-types-list">
<div class="document-type-row {{getTypeRowClass(docType)}}"
ng-click="selectType(docType)"
ng-repeat="docType in documentTypes">
<span ng-if="hasInfo(docType)">*</span>
{{docType.type}}
</div>
</div>
<div class="document-type-row add-type-layer">
<input type="text"
ng-model="documentNewType"
placeholder="{{'documents.headers.TYPE' | translate}}"/>
<div ng-click="addNewType()" class="btn btn-primary">
{{'documents.buttons.ADD_TYPE' | translate}}
</div>
</div>
</div>
</div>
<form id="upload-new-doc-container" name="form" class="col-md-4">
<div>
<label>{{'documents.headers.DOCUMENT_NAME' | translate}}: </label>
<input id="new-doc-name"
type="text"
placeholder="{{'documents.headers.DOCUMENT_NAME' | translate}}"
ng-model="documentName" />
</div>
<div ngf-drop="uploadFile($file)"
ng-model="files"
ngf-drag-over-class="'dragover'"
ngf-select="uploadFile($file)"
ngf-pattern="'.pdf,.docx,.doc,.xlsx,.xls,.odt,.ods'"
ngf-max-size="20MB"
class="drop-box">{{'documents.headers.SELECT_DOCUMENT' | translate}}</div>
</form>
</div>
<div class="row">
<div class="col-md-3">
<div ng-if="hasInfo(selectedType)" class="alert alert-info doc-type-info">
<span class="glyphicon glyphicon-info-sign"></span>
{{selectedType.type}}: {{ 'documents.messages.TYPE_INFO_' + selectedType.idDocumentType | translate }}
</div>
<div class="alert alert-info doc-type-info">
<span class="glyphicon glyphicon-info-sign"></span>
{{ 'documents.messages.TYPE_INFO' | translate }}
</div>
</div>
</div>

View File

@@ -0,0 +1,71 @@
<div class="documents-link-layer row">
<div class="all-packages-layer col-md-4">
<div class="documents-container">
<div class="documents-header">{{ 'documents.headers.SELECT_PACKAGE' | translate }}</div>
<div class="documents-list">
<div ng-click="selectPackage(package)" class="package-layer {{getPackageClass(package)}}" ng-repeat="package in packages">
<span class="flag-icon flag-icon-{{package.countryCode}}"></span> {{package.packageName}}
</div>
</div>
</div>
</div>
<div class="documents-link-area col-md-8">
<div class="documents-big-container col-md-12">
<div class="col-md-6">
<div id="linked-documents"
class="documents-container"
data-drop="true"
jqyoui-droppable="{onDrop:'documentDropped(\'linked-documents\')'}">
<div class="documents-header">{{ 'documents.headers.LINKED_DOCUMENTS' | translate }}</div>
<div id='linked-documents-list' class="documents-list">
<div class="linked-documents-layer document-row linked"
ng-repeat="document in selectedPackage.documents"
data-drag="true"
id-document="{{document.idDocument}}"
drop-to="all-documents"
jqyoui-draggable="{animate:true, onStart:'documentDragStart(\'linked-documents-list\')', onStop:'documentDragStop(\'linked-documents-list\')', scroll: false}"
data-jqyoui-options="{revert: true}">
<div class="document-icon-layer">
<span class="{{document.extension}} document-icon glyphicon glyphicon-file"></span>
<div class="document-icon-text">{{document.extension}}</div>
</div>
({{document.documentType}}) {{document.documentName}}
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div id="all-ducuments"
class="documents-container"
data-drop="true"
jqyoui-droppable="{onDrop:'documentDropped(\'all-documents\')'}">
<div class="documents-header">{{ 'documents.headers.ALL_DOCUMENTS' | translate }}</div>
<div id='all-documents-list' class="documents-list">
<div ng-if="document.isNotLinked"
class="all-documents-layer document-row not-linked"
ng-repeat="document in documents"
data-drag="true"
id-document="{{document.idDocument}}"
drop-to="linked-documents"
jqyoui-draggable="{animate:true, onStart:'documentDragStart(\'all-documents-list\')', onStop:'documentDragStop(\'all-documents-list\')', scroll: false}"
data-jqyoui-options="{revert: true}">
<div class="document-icon-layer">
<span class="{{document.extension}} document-icon glyphicon glyphicon-file"></span>
<div class="document-icon-text">{{document.extension}}</div>
</div>
({{document.documentType}}) {{document.documentName}}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="documents-link-buttons col-md-12">
<div class="btn btn-primary" ng-click="updatePackageDocuments()">
{{ 'documents.buttons.SAVE' | translate }}
</div>
</div>
</div>

View File

@@ -0,0 +1,24 @@
<button type="button"
id="documents-view"
subModule="documentsView"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'documents.buttons.VIEW_DOCUMENTS' | translate }}</button>
<?php
if($user->getUserType() === USER_TYPES['BROKER']){
require_once('AddDocumentsButton.php');
require_once('LinkDocumentsButton.php');
}
?>
<div class="row">
<div class="col-md-12"
id="documents-view-layer"
ng-if="isSubmoduleVisible('documentsView')">
<documents-view ng-controller="documentsViewCtrl" ng-init="getDocuments()"></documents-view>
</div>
</div>
<?php
if($user->getUserType() === USER_TYPES['BROKER']){
require_once('AddDocumentsLayer.php');
require_once('LinkDocumentsLayer.php');
}
?>

View File

@@ -0,0 +1,46 @@
<div class="documents-view-layer row">
<div class="document-categ col-md-12" ng-repeat="(category, categDocuments) in documents">
<h3>{{category}}</h3>
<div class="document-layer row" ng-repeat="document in categDocuments">
<div class="document-icon-layer col-md-1 col-sm-1">
<span class="{{document.extension}} document-icon glyphicon glyphicon-file"></span>
<div class="document-icon-text">{{document.extension}}</div>
</div>
<div class="document-name col-md-3 col-sm-3">
{{document.documentName}}.{{document.extension}}
</div>
<div class="packages-link col-md-6 col-sm-4">
<div ng-if="document.packages.length">
{{ 'documents.headers.LINKED_PACKAGES' | translate }} <span ng-repeat="package in document.packages">{{package.packageName}}, </span>
</div>
</div>
<div class="document-download col-md-1 col-sm-2">
<a href="utils/api/downloadFile?idDocument={{document.idDocument}}&fileName={{document.documentName}}.{{document.extension}}">
<div class="btn btn-primary">
<span class="glyphicon glyphicon-download"></span> {{ 'documents.buttons.DOWNLOAD' | translate }}
</div>
</a>
</div>
<div class="document-delete col-md-1 col-sm-2">
<div class="btn btn-danger" ng-click="showHideRemoveDialog(document)">
<span class="glyphicon glyphicon-remove"></span> {{ 'documents.buttons.REMOVE' | translate }}
</div>
</div>
</div>
</div>
</div>
<div id="dialog-confirm-remove"
dialog
ng-if="isRemoveDialogVisible"
on-confirmation="removeDocument"
on-close="showHideRemoveDialog"
is-modal="true"
has-buttons="true"
parameters="selectedDocument"
title="{{'documents.headers.REMOVE_DOCUMENT' | translate}}">
<p><span class="glyphicon glyphicon-warning-sign"></span>{{'documents.messages.REMOVE_DOCUMENT' | translate}} {{selectedDocument.documentName}}.{{selectedDocument.extension}}?</p>
</div>

View File

@@ -0,0 +1,5 @@
<button type="button"
id="documents-link"
subModule="documentsLink"
class="btn btn-default"
ng-click="setSubModule($event)">{{ 'documents.buttons.LINK_DOCUMENT' | translate }}</button>

View File

@@ -0,0 +1,7 @@
<div class="row">
<div class="col-md-12"
id="documents-link-layer"
ng-if="isSubmoduleVisible('documentsLink')">
<documents-link ng-controller="documentsLinkCtrl" ng-init="getDocumentsAndPackages()"></documents-link>
</div>
</div>

View File

@@ -0,0 +1,76 @@
<?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));
}
/**
* get customers and their discount
* @return json values for customers and dicounts
*/
public function getCustomersAndDiscount(){
echo json_encode($this->model->getCustomersAndDiscount());
}
/**
* save customers discount
* @return json update message
*/
public function saveCustomersDiscount() {
$discounts = isset($_REQUEST['discounts']) ? $_REQUEST['discounts'] : [];
echo json_encode($this->model->saveCustomersDiscount($discounts));
}
/**
* include financing template
*/
public function financingTemplate() {
require_once('templates/FinancingTempalte.php');
}
/**
* include set interest rate template
*/
public function setInterestRateTemplate() {
require_once('templates/SetInterestRateTemplate.php');
}
public function setCustomersDiscountTemplate() {
require_once('templates/SetCustomersDiscountTemplate.php');
}
/**
* open financing page
*/
public function showPage(){
require_once('FinancingPage.php');
}
}

View File

@@ -0,0 +1,52 @@
<?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);
}
/**
* get customers discount
* @return HashArray customers discount
*/
public function getCustomersAndDiscount() {
$interestRate = new InterestRate();
return $interestRate->getCustomersAndDiscount();
}
/**
* save discount for customer - financing
* @param Array $discounts id of the customer and the discount applied for each
* @return Array update message
*/
public function saveCustomersDiscount($discounts) {
$interestRate = new InterestRate();
return $interestRate->saveCustomersDiscount($discounts);
}
}

View File

@@ -0,0 +1,8 @@
<script src="<?php echo PATH_JS_COMPONENTS.'financing/financing.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'financing/set-interest-rate.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'financing/set-customers-discount.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<div id="financing-module" class="container-fluid col-md-12">
<h1>{{ 'financing.TITLE' | translate }}</h1>
<financing ng-controller="financingController" ng-init="getInterestRate()"></financing>
</div>

View File

@@ -0,0 +1,158 @@
<?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
* @param Int $idCustomer the id of the customer for which to take the inters rate for
* @return HashArray interest rate value for every customer or specific customer in the system
*/
public function getInterestRateForCustomers($idCustomer = 0){
global $database;
$data = [];
$interestRate = $this->getInterestRate()['interestRate'];
$whereSql = $idCustomer ? "WHERE rcd.idCustomer=".$idCustomer : '';
$sql = "SELECT
rcd.discount,
rcd.idCustomer
FROM
".TABLES['rel_customer_discount']." rcd
$whereSql";
$query = $database->query($sql);
while($row = $database->fetchArray($query)) {
$data[$row['idCustomer']] = $interestRate - $row['discount'];
}
return $idCustomer && isset($data[$idCustomer]) ? $data[$idCustomer] : $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
ORDER BY c.name";
$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' => 'warning',
'message' => 'CUSTOMERS_DISCOUNT_EMPTY'
];
return $data;
}
foreach($details as $customerDiscounts) {
$discount = floatval($customerDiscounts['discount']);
if($discount > $interestRate || $discount < 0) {
$data['messages'][] = [
'code' => 'error',
'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,28 @@
<button type="button"
id="set-interest-rate-btn"
subModule="setInterestRate"
class="btn btn-default"
ng-click="setSubModule($event)">Interest rate</button>
<button type="button"
id="set-discount-for-customers-btn"
subModule="setCustomersDiscount"
class="btn btn-default"
ng-click="setSubModule($event)">Customers discount</button>
<div class="row">
<div class="col-sm-12"
id="set-interest-rate-layer"
ng-if="isSubmoduleVisible('setInterestRate')">
<h3>Set interest rate</h3>
<set-interest-rate ng-controller="setInterestRateCtrl" ng-init="getInterestRate()"></set-interest-rate>
</div>
</div>
<div class="row">
<div class="col-sm-12"
id="set-customers-discount-layer"
ng-if="isSubmoduleVisible('setCustomersDiscount')">
<h3>Set customers discount</h3>
<set-customers-discount ng-controller="setCustomersDiscountCtrl" ng-init="getCustomersAndDiscount()"></set-customers-discount>
</div>
</div>

View File

@@ -0,0 +1,37 @@
<div id="set-customers-discount-module-container">
<div class="row">
<div class="interest-rate col-md-12">
<h4 class="col-md-2">Customer name</h4>
<h4 class="col-md-1">Discount</h4>
<h4 class="col-md-2">New financing rate</h4>
</div>
<div ng-repeat="customerDetails in customers track by customerDetails.idCustomer">
<div class="customer-info-discount col-md-12">
<span class="col-md-2">{{::customerDetails.name}}</span>
<div class="customer-discount col-md-1">
<input id="discount-input-{{customerDetails.idCustomer}}"
class="edit-interest-rate-discount"
type="number"
placeholder="0"
name="customerDiscount"
ng-model="discounts[customerDetails.idCustomer]"
ng-model-options="{ allowInvalid: true}"
min="0"
max="{{interestRate-0.01}}"
step="0.01" />
%
</div>
<span class="col-md-2">{{getNewInterestRate(customerDetails.idCustomer)}} %</span>
</div>
<div class="col-md-12 customer-discount-message" ng-if="showMessage">
<span class="col-md-offset-1 alert alert-warning">
Value should be between 0 and {{getMaxInterestRateValue()}} with maximum 2 decimals
</span>
</div>
</div>
<div class="col-md-12">
<div class="btn btn-primary" ng-click="saveCustomersDiscount()">Save</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,15 @@
<div id="set-interest-rate-container">
<div class="row">
<div class="interest-rate col-md-4">
<label>Interest rate: </label>
<input id="interest-rate-input"
class="edit-interest-rate"
type="text"
placeholder="Interest rate"
ng-model="interestRate" /> %
</div>
<div class="col-md-12">
<div class="btn btn-primary" ng-click="saveInterestRate()">Save</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,8 @@
<?php
class HomeController{
public function showPage(){
echo 'Home page';
}
}
?>

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,27 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', TRUE);
ini_set('display_startup_errors', TRUE);
date_default_timezone_set('Europe/Stockholm');
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
// Redirect output to a clients web browser (Excel2007)
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Cache-Control: max-age=0');
// If you're serving to IE 9, then the following may be needed
header('Cache-Control: max-age=1');
// If you're serving to IE over SSL, then the following may be needed
header ('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
header ('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); // always modified
header ('Cache-Control: cache, must-revalidate'); // HTTP/1.1
header ('Pragma: public'); // HTTP/1.0
$route::call($module, $controller, $action);
exit;
?>

View File

@@ -0,0 +1,6 @@
<?php
header('Content-Type: text/html; charset=utf-8');
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
$route::call($module, $controller, $action);

View File

@@ -0,0 +1,37 @@
<?php
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
?>
<nav id="nav-menu" class="navbar navbar-default">
<div class="container-fluid">
<div id="nav-menu-header" class="navbar-header">
<a id="nav-app-title" class="navbar-brand" href="#"><?php echo APPLICATION_NAME;?></a>
</div>
<ul id="nav-buttons" class="nav navbar-nav">
<?php
foreach($route::getModules()['modules'] as $page) {
$class = $module === $page['url'] ? 'class="active"' : '';
echo '<li id="nav-button-'.$page['url'].'" ' . $class . '><a href="' . $page['url'] . '">{{ "main.menu.' . $page['name'] . '" | translate }}</a></li>';
}
?>
</ul>
<ul id="nav-right" class="nav navbar-nav navbar-right">
<?php
if($user->getUserType() === USER_TYPES['CUSTOMER']){
require_once('templates/ShopCartIconTemplate.php');
}
?>
<li><a><translate-main ng-controller="translateCtrl"></translate-main></a></li>
<li id="nav-settings">
<a href="profileSettings">
<span class="glyphicon glyphicon-user"></span><?php echo ' ' . $user->getUserFullName() . ' (' . $user->getUserType() . ')';?>
<span class='glyphicon glyphicon-cog'></span>
</a>
</li>
<li id="nav-logout">
<a href="logout.php"><span class="glyphicon glyphicon-log-out"></span> {{ 'main.LOGOUT' | translate }}</a>
</li>
</ul>
</div>
</nav>

View File

@@ -0,0 +1,47 @@
<?php
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
?>
<!doctype html>
<html ng-app='dashApp'>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title><?php echo APPLICATION_NAME;?></title>
<link rel="shortcut icon" type="image/png" href="client/img/wiaas_icon.png"/>
<?php
if($module !== 'login'){
require_once('templates/cssIncludes.php');
require_once('templates/jsIncludes.php');
}else{
require_once('templates/loginCssIncludes.php');
require_once('templates/loginJsIncludes.php');
}
?>
</head>
<body>
<div id="wrapper" class="wrapper">
<?php
if(!$user->isLoggedIn() && $module !== 'login'){
header('Location:login');
die();
}
if($module !== 'login'){
require_once('menuTemplate.php');
}
$route::call($module, $controller, $action);
if($module !== 'login'){
echo '<activity-checker ng-init="checkLastActivity()" ng-controller="activityCheckerCtrl"></activity-checker>';
require_once('templates/FooterTemplate.php');
}
?>
</div>
</body>
</html>

View File

@@ -0,0 +1,5 @@
<?php
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
$route::call($module, $controller, $action, $apiKey);

View File

@@ -0,0 +1,3 @@
<footer class="footer col-md-12">
<a target="_blank" href="terms/html/pdfTerms">{{'main.TERMS' | translate}}</a>
</footer>

View File

@@ -0,0 +1,5 @@
<li id="nav-cart">
<a href="shop?subModule=cart">
<div ng-controller="shopCartIconCtrl" class="cart-notificaiton"><span class="glyphicon glyphicon-shopping-cart"></span> <span ng-if="hasPackagesInCart()">{{shopCartItemsCount}}</span></div>
</a>
</li>

View File

@@ -0,0 +1,11 @@
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_JS_LIBS.'bootstrap/dist/css/bootstrap.css';?>"/>
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_JS_LIBS.'datatables.net-bs/css/dataTables.bootstrap.min.css';?>"/>
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_JS_LIBS.'datatables.net-responsive-dt/css/responsive.dataTables.min.css';?>"/>
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_JS_LIBS.'angular-ui-notification/dist/angular-ui-notification.min.css';?>"/>
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_JS_LIBS.'jquery-ui/jquery-ui.min.css';?>"/>
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_JS_LIBS.'jquery-ui/jquery-ui.theme.min.css';?>"/>
<link href="<?php echo PATH_JS_LIBS.'flag-icon-css-master/css/flag-icon.css?v='.APPLICATION_VERSION;?>" rel="stylesheet">
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_CSS.'style.less?v='.APPLICATION_VERSION;?>"/>
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_CSS.'/dist/bundle.min.css?v='.APPLICATION_VERSION;?>" />

View File

@@ -0,0 +1,32 @@
<script src="<?php echo PATH_JS_LIBS.'jquery/dist/jquery.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'less/dist/less.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'bootstrap/dist/js/bootstrap.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular/angular.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-translate/angular-translate.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-translate-loader-url/angular-translate-loader-url.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'clipboard/dist/clipboard.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'ngclipboard/dist/ngclipboard.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'datatables.net/js/jquery.dataTables.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'datatables.net-bs/js/dataTables.bootstrap.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'datatables.net-responsive/js/dataTables.responsive.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-ui-notification/dist/angular-ui-notification.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-ui-sortable/sortable.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'jquery-ui/jquery-ui.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-dragdrop/src/angular-dragdrop.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'ng-file-upload/ng-file-upload.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'tinymce/tinymce.min.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-ui-tinymce/src/tinymce.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS.'app.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS.'errorHandlerFactory.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'errors/errorsDialog.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS.'constants.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'translate/translate.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'activity/activityChecker.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'datepicker/datepicker.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dataTableHelper/dataTableHelper.service.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'utils.service.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'dialog/dialog.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'sortable/sortable.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'shop/shop-cart.service.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>

View File

@@ -0,0 +1,2 @@
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_JS_LIBS.'bootstrap/dist/css/bootstrap.css';?>"/>
<link rel="stylesheet/less" type="text/css" href="<?php echo PATH_CSS.'style.less?v='.APPLICATION_VERSION;?>"/>

View File

@@ -0,0 +1,8 @@
<script src="<?php echo PATH_JS_LIBS.'jquery/dist/jquery.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'less/dist/less.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'bootstrap/dist/js/bootstrap.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular/angular.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-translate/angular-translate.min.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_LIBS.'angular-translate-loader-url/angular-translate-loader-url.js';?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS.'login.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>

View File

@@ -0,0 +1,42 @@
<?php
class LoginController{
public function getToken(){
global $user;
if(isset($_POST['login'])){
$login = $user->login($_POST['username'], $_POST['password'], true);
echo json_encode($login);
}else{
echo json_encode(['status' => 'fail', 'errorMessage' => 'invalid request']);
}
}
public function validateToken(){
global $user;
if($user->isLoggedIn()){
$message = ['status' => 'success'];
}else{
$message = ['status' => 'fail', 'errorMessage' => $user->getErrorMessage()];
}
echo json_encode($message);
}
public function getModules(){
global $user, $route;
if($user->isLoggedIn()){
echo json_encode(['modules' => $route::getModules()]);
}else{
echo json_encode(['modules' => []]);
}
}
/**
* open packages page
*/
public function showPage(){
global $user;
require_once('LoginPage.php');
}
}
?>

View File

@@ -0,0 +1,26 @@
<?php
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
if($user->isLoggedIn()){
header('Location:dashboards');
}
if(isset($_REQUEST['generate']) && $_REQUEST['generate'] === 'newToken') {
include('templates/ForgotPasswordForm.php');
} else if(isset($_REQUEST['token'])) {
$confirmTokenMessage = $user->checkPasswordToken($_REQUEST['token']);
if($confirmTokenMessage === 'success') {
include('templates/ResetPasswordForm.php');
} else {
echo '<div id="confirmation-message" class="col-sm-4 col-sm-offset-4 password-confirmation-messages alert alert-danger">';
echo '<span class="glyphicon glyphicon-alert"></span> {{"validation.messages.INVALID_TOKEN" | translate}}';
echo '</div>';
echo '<div id="back-to-sign-in" class="col-sm-4 col-sm-offset-4 back-to-sign-in-btn alert alert-info">';
echo '<a href="login">{{"validation.buttons.SIGN_IN" | translate}}</a>';
echo '</div>';
}
} else {
include('templates/LoginForm.php');
}

View File

@@ -0,0 +1,50 @@
<?php
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
if(isset($_POST['forgetPassword']) && isset($_POST['mail']) && $_POST['mail']){
$confirmMessages = isset($_POST['mail']) ? $user->forgotPassword($_POST['mail']) : 'ERROR';
}
?>
<div class="row">
<div class="wiaas-title col-sm-12">
<h1>{{ 'login.headers.TITLE' | translate }}</h1>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-sm-offset-4">
<form id="forget-passwd-form" action="" method="post" class="form-signin">
<h2 class="form-signin-heading">{{ 'login.headers.FORGET_PASSWORD_TITLE' | translate }}</h2>
<label for="mail" class="sr-only">{{ 'login.headers.MAIL' | translate }}</label>
<input id="forgotten-mail" name="mail" type="text" class="form-control" placeholder="{{ 'login.headers.MAIL' | translate }}" required autofocus />
<button id="login-button" type="submit" name="forgetPassword" class="btn btn-lg btn-primary btn-block">{{ 'login.buttons.SEND_RECOVER_MAIL' | translate }}</button>
</form>
<?php
if(isset($confirmMessages)) {
foreach ($confirmMessages as $key => $confirmMessage) {
$translatedMessage = '{{"login.messages.'.$confirmMessage.'" | translate}}';
$alertClass = 'alert-danger';
$iconClass = 'glyphicon-alert';
if($confirmMessage === 'SIGN_IN') {
$alertClass = 'alert-success';
$iconClass = 'glyphicon-ok';
$translatedMessage = '{{"login.messages.MAIL_SENT" | translate}}';
} else if($confirmMessage === 'NO_USER' || $confirmMessage === 'CHANGE_LATER') {
$alertClass = 'alert-warning';
}
$translatedMessage .= ' <a href="login">{{"login.messages.SIGN_IN" | translate}}</a>';
echo '<div id="confirmation-message" class="alert '.$alertClass.'">';
echo 'User '. ($key+1). ' : ';
echo '<span class="glyphicon '.$iconClass.'"></span> '.$translatedMessage;
echo '</div>';
}
}
?>
</div>
</div>

View File

@@ -0,0 +1,50 @@
<?php
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
if(isset($_POST['login'])){
$loginMessage = $user->login($_POST['username'], $_POST['password']);
if($loginMessage['status'] === 'success'){
header('Location:dashboards');
}
}
$message = (isset($_REQUEST['message'])) ? $_REQUEST['message'] : '';
?>
<div class="row">
<div class="wiaas-title col-sm-12">
<h1><?php echo APPLICATION_NAME;?> {{ 'login.headers.TITLE' | translate }}</h1>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-sm-offset-4">
<form id="login-form" action="" method="post" class="form-signin">
<h2 class="form-signin-heading">{{ 'login.headers.SMALL_TITLE' | translate }}</h2>
<label for="username" class="sr-only">{{ 'login.headers.USERNAME' | translate }}</label>
<input id="username" name="username" type="text" id="username" class="form-control" placeholder="{{ 'login.headers.USERNAME' | translate }}" required autofocus>
<label for="inputPassword" class="sr-only">{{ 'login.headers.PASSWORD' | translate }}</label>
<input id="password" name="password" type="password" id="inputPassword" class="form-control" placeholder="{{ 'login.headers.PASSWORD' | translate }}">
<button id="login-button" name="login" class="btn btn-lg btn-primary btn-block" type="submit">{{ 'login.buttons.SIGN_IN' | translate }}</button>
</form>
<?php
if(isset($loginMessage['errorMessage'])){
echo '<div id="login-message" class="alert alert-warning">';
echo '<span class="glyphicon glyphicon-warning-sign"></span> {{"login.messages.'.$loginMessage['errorMessage'].'" | translate}}';
if($loginMessage['errorMessage'] === 'INVALID_USERNAME_PASSWORD') {
echo " <a href='?generate=newToken'>{{'login.headers.FORGET_PASSWORD' | translate}}</a>";
}
echo '</div>';
}
if($message){
echo '<div id="login-message" class="alert alert-success">';
echo '<span class="glyphicon glyphicon-ok"></span> {{"validation.messages.'.$message.'" | translate}}';
echo '</div>';
}
?>
</div>
</div>
<span id="application-version-login" style="display:none;"><?php echo APPLICATION_VERSION; ?></span>

View File

@@ -0,0 +1,58 @@
<?php
if(!defined('APPLICATION_VERSION')){
die("Permission denied!");
}
if(isset($_POST['resetPassword']) && isset($_POST['newPassword']) && isset($_POST['confirmPassword'])){
if(!empty($_POST['newPassword'] && !empty($_POST['confirmPassword']))) {
$passwords = [
'newPassword' => $_POST['newPassword'],
'confirmPassword' => $_POST['confirmPassword']
];
$confirmationData = $user->resetPassword(json_encode($passwords));
} else {
$confirmationData['messages'][] = [
'code' => 'error',
'message' => 'PASSWORDS_MISSING'
];
}
}
?>
<div class="row">
<div class="wiaas-title col-sm-12">
<h1><?php echo APPLICATION_NAME;?></h1>
</div>
</div>
<div class="row">
<div class="col-sm-4 col-sm-offset-4">
<form id="reset-password-form" action="" method="post" class="form-signin">
<?php
echo '<h2 class="form-signin-heading">{{ "validation.headers.RESET_TITLE" | translate }} - <b>'.$user->getSetPasswordUsername().'</b></h2>';
?>
<div class="alert alert-info">
<span class="glyphicon glyphicon-info-sign"></span>
{{'validation.messages.PASSWORD_CHARACTERS' | translate}}
</div>
<label for="passwd" class="sr-only">{{ 'validation.headers.NEW_PASSWORD' | translate }}</label>
<input id="new-passwd" name="newPassword" type="password" class="form-control" placeholder="{{ 'validation.headers.NEW_PASSWORD' | translate }}" required autofocus />
<label for="confirmPasswd" class="sr-only">{{ 'validation.headers.CONFIRM_PASSWORD' | translate }}</label>
<input id="confirm-passwd" name="confirmPassword" type="password" class="form-control" placeholder="{{ 'validation.headers.CONFIRM_PASSWORD' | translate }}" required />
<button id="reset-password-button" type="submit" name="resetPassword" class="btn btn-lg btn-primary btn-block">{{ 'validation.buttons.SET_PASSWORD' | translate }}</button>
</form>
<?php
if(isset($confirmationData) && $confirmationData['messages']) {
foreach($confirmationData['messages'] as $position => $messageData) {
if($messageData['code'] === 'success' && $messageData['message'] === 'PASSWORD_GENERATED') {
header('Location:login?message='.$messageData['message']);
} else {
echo '<div id="confirmation-message-'.$position.'" class="password-confirmation-messages alert alert-danger">';
echo '<span class="glyphicon glyphicon-alert"></span> {{"validation.messages.'.$messageData['message'].'" | translate}}';
echo '</div>';
}
}
}
?>
</div>
</div>

View File

@@ -0,0 +1,92 @@
<?php
class OrderProjects{
public function getOrderProjectsHeaders($type = 'array'){
$headersHelper = new HeadersHelper();
$data = [];
$headers = [
'op.id' => 'idProject',
'op.name' => 'projectName',
'op.isAvailable' => 'isAvailable'
];
$data['headers'] = $headersHelper->getHeader($headers, $type);
return $data;
}
public function getOrderProjects($available = 1){
global $database;
$data = [];
$headersSql = $this->getOrderProjectsHeaders('sql')['headers'];
$whereSql = intval($available) === 1 ? " AND op.isAvailable=1" : "";
$sql = "SELECT
$headersSql
FROM ".TABLES['order_projects']." op
WHERE 1=1 $whereSql
ORDER BY op.name ASC";
$data['data'] = $database->fetchResultArray($sql);
return $data;
}
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;
}
}

View File

@@ -0,0 +1,31 @@
<?php
class OrderProjectsController{
private $model;
function __construct(){
$this->model = new OrderProjectsModel();
}
public function getOrderProjectsHeaders(){
echo json_encode($this->model->getOrderProjectsHeaders(), JSON_NUMERIC_CHECK);
}
public function getOrderProjects(){
$available = isset($_REQUEST['available']) ? $_REQUEST['available'] : '';
echo json_encode($this->model->getOrderProjects($available), JSON_NUMERIC_CHECK);
}
public function editOrderProject(){
$projectData = isset($_REQUEST['projectData']) ? $_REQUEST['projectData'] : '[]';
echo json_encode($this->model->editOrderProject($projectData), JSON_NUMERIC_CHECK);
}
public function orderProjectsEditTemplate() {
require_once('templates/OrderProjectsEditTemplate.php');
}
public function orderProjectsTemplate() {
require_once('templates/OrderProjectsTemplate.php');
}
}

View File

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

View File

@@ -0,0 +1,41 @@
<div id="order-projects-edit" class="row">
<form class="col-md-6">
<div class="form-group col-md-12">
<label class="col-md-2" for="projectName">Project Name</label>
<input class="col-md-4"
type="text"
class="form-control"
id="projectName"
placeholder="Project Name"
ng-model="data.projectName"
value="{{data.projectName}}"
autofocus>
</div>
<div class="form-check col-md-12">
<label class="col-md-2" for="projectName">Is Available</label>
<div class="col-md-4">
<input class="form-check-input"
type="radio" name="isAvailable"
id="isAvailable-yes"
ng-model="data.isAvailable"
value="1">
<label class="form-check-label" for="isAvailable">Yes</label>
<input class="form-check-input"
type="radio"
name="isAvailable"
id="isAvailable-no"
ng-model="data.isAvailable"
value="0">
<label class="form-check-label" for="isAvailable">No</label>
</div>
</div>
<div class="form-group col-md-12">
<div class="col-md-12">
<button ng-click="editOrderProject()" class="btn btn-primary">Edit Project</button>
</div>
</div>
</form>
</div>

View File

@@ -0,0 +1 @@
<table class="table table-bordered table-striped table-hover" id="order-projects-table"></table>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,270 @@
<?php
/**
* OrderActions - helper class to handle automatic actions from steps
*/
class OrderActions{
private $idAssignProcessStep = 2;
/**
* execute automated step
* @param INT $idOrder id for the order
* @param INT $idProcessStep id for the process step
* @return INT execution status; 1 for success and 0 for fail
*/
public function executeAutomatedStep($idOrder, $idProcessStep){
global $database;
$status = [];
$sql = "SELECT psa.actionCode, psa.stepType, ps.id as idProcessStep
FROM ".TABLES['process_step']." ps
INNER JOIN ".TABLES['process_step_actions']." psa
ON psa.id=ps.idActionCode
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.idStep=ps.id
WHERE rps.id=$idProcessStep
LIMIT 1";
$step = $database->fetchResultArray($sql);
if($step && count($step) > 0){
$status['actionExectution'] = $this->{ $step[0]['actionCode'] }($idOrder, $idProcessStep);
$childSteps = $this->getStepChilds($idProcessStep);
$status['updateCurrentStep'] = $this->updateActiveStep($idOrder, $idProcessStep, $childSteps);
foreach ($childSteps as $child) {
if($child['stepType'] === 'auto'){
return $this->executeAutomatedStep($idOrder, $child['idProcessStep']);
}else{
return $status['actionExectution'] > 0 && $status['updateCurrentStep'] > 0 ? 1 :0;
}
}
}else{
return 0;
}
}
/**
* update the status for the step in progress
* @param INT $idOrder id for the order
* @param INT $idProcessStep id for the process step
* @return INT affected rows
*/
public function updateActiveStep($idOrder, $idProcessStep, $childSteps){
global $database;
$sqlUpdateCurrentStep = "UPDATE ".TABLES['rel_order_process_step']."
SET status='done',
actualDate = IF(actualDate IS NULL, '".date("Y-m-d")."', actualDate)
WHERE idOrder=$idOrder
AND idProcessStep=$idProcessStep
";
$query = $database->query($sqlUpdateCurrentStep);
$status['current'] = $database->affectedRows();
$childValues = '';
if(count($childSteps) > 0){
foreach ($childSteps as $child) {
$childValues .= $child['idProcessStep'].',';
}
$childValues = rtrim($childValues, ',');
$sqlUpdateChilds = "UPDATE ".TABLES['rel_order_process_step']."
SET status='in-progress'
WHERE idOrder=$idOrder AND idProcessStep IN($childValues)";
$query = $database->query($sqlUpdateChilds);
$status['child'] = $database->affectedRows();
}else{
$status['child'] = 1;
}
return $status['current'] > 0 && $status['child'] > 0 ? 1 : 0;
}
/**
* remove a process from a package inan order
* @param INT $idOrder id for the order
* @return INT number of affected rows
*/
private function removeProcess($idOrder){
global $database;
$sql = "DELETE FROM ".TABLES['rel_order_process_step']."
WHERE idOrder=$idOrder";
$query = $database->query($sql);
$affectedRows = $database->affectedRows();
$sql = "UPDATE ".TABLES['rel_order_packages']."
SET status='no-process'
WHERE idOrder=$idOrder";
$query = $database->query($sql);
$affectedRows += $database->affectedRows();
$sql = "UPDATE ".TABLES['orders']."
SET status='open'
WHERE id=$idOrder";
$query = $database->query($sql);
$affectedRows += $database->affectedRows();
return $affectedRows;
}
/**
* undo an open step
* @param INT $idOrder id for the order
* @param INT $idProcessStep id for the process step
* @return INT 1 in case the step has benn undone and 0 in case of failure
*/
public function undoStep($idOrder, $idProcessStep){
global $database;
$database->beginTransaction();
$sqlUpdateCurrentStep = "
UPDATE ".TABLES['rel_order_process_step']."
SET status='inactive'
WHERE idOrder=$idOrder
AND idProcessStep=$idProcessStep
";
$query = $database->query($sqlUpdateCurrentStep);
$status['current'] = $database->affectedRows();
$sql = "SELECT parent.idStep
FROM ".TABLES['rel_process_steps']." parent
INNER JOIN ".TABLES['rel_process_steps']." current
ON current.idParent=parent.id
WHERE current.id=$idProcessStep";
$step = $database->fetchResultArray($sql)[0];
if(intval($step['idStep']) === $this->idAssignProcessStep){
$status['parent'] = $this->removeProcess($idOrder);
}else{
$sqlUpdateParent = "
UPDATE ".TABLES['rel_order_process_step']."
SET status='in-progress'
WHERE idOrder=$idOrder
AND idProcessStep=(SELECT idParent
FROM ".TABLES['rel_process_steps']."
WHERE id=$idProcessStep)";
$query = $database->query($sqlUpdateParent);
$status['parent'] = $database->affectedRows();
}
if($status['current'] < 1 && $status['parent'] < 1){
$database->rollback();
return 0;
}
$database->commit();
return 1;
}
/**
* get childs for a step
* @param INT $idProcessStep id for the process step
* @return Array Array with childs
*/
public function getStepChilds($idProcessStep){
global $database;
$sqlChilds = "SELECT rps.id AS idProcessStep,
psa.actionCode,
psa.stepType
FROM ".TABLES['rel_process_steps']." rps
INNER JOIN ".TABLES['process_step']." ps
ON ps.id=rps.idStep
INNER JOIN ".TABLES['process_step_actions']." psa
ON psa.id=ps.idActionCode
WHERE rps.idParent=$idProcessStep";
return $database->fetchResultArray($sqlChilds);
}
/**
* update the current step and activate childs (execute automated steps if they exist)
* @param INT $idOrder id for the order
* @param INT $idPackage id for the package
* @param INT $idProcessStep id for the process step
* @return Array number of update childs and executed automated steps
*/
public function updateChildSteps($idOrder, $idPackage, $idProcessStep){
global $database;
$childsUpdated = [
'manual' => 0,
'automated' => 0
];
$childSteps = $this->getStepChilds($idProcessStep);
if(!empty($childSteps)){
$childValues = '';
$automatedSteps = [];
foreach ($childSteps as $child) {
if($child['stepType'] === 'auto'){
$automatedSteps[] = $child;
}
$childValues .= $child['idProcessStep'].',';
}
$childValues = rtrim($childValues, ',');
$sqlUpdateChilds = "UPDATE ".TABLES['rel_order_process_step']."
SET status='in-progress'
WHERE idOrder=$idOrder AND idPackage=$idPackage AND idProcessStep IN($childValues)";
$query = $database->query($sqlUpdateChilds);
$childsUpdated['manual'] = $database->affectedRows();
foreach ($automatedSteps as $child) {
$childActionStatus = $this->{ $child['actionCode'] }($idOrder, $idPackage, $child['idProcessStep']);
if($childActionStatus){
$childsUpdated['automated'] = $this->updateActiveStep($idOrder, $child['idProcessStep']);
$automatedNewChilds = $this->updateChildSteps($idOrder, $idPackage, $child['idProcessStep']);
}
}
}
return $childsUpdated;
}
/**
* automatic action executed for Order Placed step
* @param INT $idOrder id of the order
* @param INT $idProcessStep id of the link of the step to the process
* @return boolean result for executing automated step
*/
public function newOrder($idOrder, $idProcessStep){
global $database;
$sql = "SELECT o.orderDate
FROM ".TABLES['orders']." o
WHERE id=$idOrder";
$order = $database->fetchResultArray($sql);
if(!isset($order[0])){
$order[0]['orderDate'] = date("Y-m-d");
}
$sql = "UPDATE ".TABLES['rel_order_process_step']."
SET estimateDate='".$order[0]['orderDate']."',
actualDate='".$order[0]['orderDate']."',
status='done'
WHERE idOrder=$idOrder AND idProcessStep=$idProcessStep";
$query = $database->query($sql);
return $database->affectedRows() === 1;
}
/**
* automatic action for assign process
* @param INT $idOrder id of the order
* @return boolean result for executing automated step
*/
public function processAssigned($idOrder){
global $database;
$sql = "UPDATE ".TABLES['rel_order_packages']."
SET status='processing'
WHERE idOrder=$idOrder";
$query = $database->query($sql);
return $database->affectedRows() > 0;
}
}
?>

View File

@@ -0,0 +1,237 @@
<?php
class OrderDocuments{
const DOCUMENT_TYPES = [
'ID_QUESTIONAIRE_DOC_TYPE' => 2, // 2 => 'orderQuestionaire'
'ID_CONFIGURATION_DOC_TYPE' => 3, // 3 => 'configuration'
'ID_ACCEPTANCE_DOC_TYPE' => 5, // 5 => 'customerAcceptance'
'ID_INSTALLATION_PROTOTCOL_DOC_TYPE' => 10 // 10 => 'installationProtocol'
];
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,
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,
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;
}
/**
* upload a new file for configuration
* @param INT $idOrder id for the order
* @param INT $idPackage id for the package
* @param INT $idSupplier id for supplier
* @param STRING $fileType the type of the file (configuration or installation)
* @param FILE $file file to be uploaded
* @return Array upload message
*/
public function uploadConfigurationDocument($idOrder, $idPackage, $idSupplier, $fileType, $file){
global $database, $user;
$idOrder = $database->escapeValue($idOrder);
$idPackage = $database->escapeValue($idPackage);
$idSupplier = $database->escapeValue($idSupplier);
$fileType = $database->escapeValue($fileType);
if(!$idPackage){
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_PACKAGE'
];
return $data;
}
$idDocumentType = self::DOCUMENT_TYPES['ID_CONFIGURATION_DOC_TYPE'];
$nameSuffix = 'config';
$maxCount = 1;
$sql = "SELECT s.idUser
FROM ".TABLES['suppliers']." s
WHERE s.id=$idSupplier";
$query = $database->query($sql);
$supplier = $database->fetchArray($query);
$sql = "SELECT name
FROM ".TABLES['packages']."
WHERE id=$idPackage";
$query = $database->query($sql);
$package = $database->fetchArray($query);
$documentName = isset($package['name']) ? str_replace(' ', '_', $package['name']) : '';
$documentName .= '_'.$idSupplier.'_'.$nameSuffix;
$sql = "
SELECT
d.documentName
FROM
".TABLES['documents']." d
INNER JOIN ".TABLES['rel_order_documents']." rod
ON d.id = rod.idDocument
WHERE rod.idOrder = $idOrder
AND rod.idPackage = $idPackage
AND d.idDocumentType = $idDocumentType
ORDER BY d.id DESC
LIMIT 1";
$lastDocName = $database->fetchResultArray($sql);
if($lastDocName && $lastDocName[0]['documentName']) {
$count = explode('_', $lastDocName[0]['documentName']);
$maxCount = intval(end($count)) + 1;
}
$documentName .= '_'.$maxCount;
$idUser = $user->getUserId();
$fileManager = new FileManager();
$data = $fileManager->uploadFile($file, $idDocumentType, $documentName, $idUser, $supplier['idUser']);
if(isset($data['messages'])){
return $data;
}
$idDocument = $data['idDocument'];
$sql = "INSERT INTO ".TABLES['rel_order_documents']."
(idOrder, idPackage, idDocument, validation)
VALUES($idOrder, $idPackage, $idDocument, 'not-required')";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'FILE_UPLOADED'
];
}else{
$data['messages'][] = [
'code' => 'error',
'message' => 'NOT_UPLOADED'
];
}
return $data;
}
/**
* remove order document
* @param INT $idOrder id for order
* @param INT $idPackage id for package
* @param INT $idDocument id for document
* @return Array remove message
*/
public function removeOrderDocument($idOrder, $idPackage, $idDocument) {
global $database;
$idOrder = $database->escapeValue($idOrder);
$idPackage = $database->escapeValue($idPackage);
$idDocument = $database->escapeValue($idDocument);
$rowsDeleted = 0;
$data = [];
if(!$idDocument) {
$data['messages'][] = [
'code' => 'error',
'message' => 'DOCUMENT_NOT_SET'
];
return $data;
}
$fileManager = new FileManager();
$data = $fileManager->removeDocument($idDocument);
foreach ($data['messages'] as $messageObj) {
if ($messageObj['code'] === 'success') {
$sqlUnlink = "
DELETE
FROM ".TABLES['rel_order_documents']."
WHERE idOrder = $idOrder
AND idPackage = $idPackage
AND idDocument = $idDocument
";
$query = $database->query($sqlUnlink);
}
}
return $data;
}
}

View File

@@ -0,0 +1,544 @@
<?php
class orderExtraActions {
const DOCUMENT_TYPES = [
'ID_QUESTIONAIRE_DOC_TYPE' => 2, // 2 => 'orderQuestionaire'
'ID_CONFIGURATION_DOC_TYPE' => 3, // 3 => 'configuration'
'ID_ACCEPTANCE_DOC_TYPE' => 5, // 5 => 'customerAcceptance'
'ID_INSTALLATION_PROTOTCOL_DOC_TYPE' => 10 // 10 => 'installationProtocol'
];
const ID_INSTALLATION_CATEGORY = 2;
/**
* upload a new file for configuration
* @param INT $idOrder id for the order
* @param INT $idPackage id for the package
* @param INT $idSupplier id for supplier
* @param STRING $fileType the type of the file (configuration or installation)
* @param FILE $file file to be uploaded
* @return Array upload message
*/
public function uploadConfigurationDocument($idOrder, $idPackage, $idSupplier, $fileType, $file){
global $database, $user;
$idSupplier = $database->escapeValue($idSupplier);
$fileType = $database->escapeValue($fileType);
$idDocumentType = self::DOCUMENT_TYPES['ID_CONFIGURATION_DOC_TYPE'];
$nameSuffix = 'config';
$maxCount = 1;
if($fileType === 'installationProtocol') {
$idDocumentType = self::DOCUMENT_TYPES['ID_INSTALLATION_PROTOTCOL_DOC_TYPE'];
$nameSuffix = 'install_protocol';
}
$sql = "SELECT s.idUser
FROM ".TABLES['suppliers']." s
WHERE s.id=$idSupplier";
$query = $database->query($sql);
$supplier = $database->fetchArray($query);
$sql = "SELECT name
FROM ".TABLES['packages']."
WHERE id=$idPackage";
$query = $database->query($sql);
$package = $database->fetchArray($query);
$documentName = isset($package['name']) ? str_replace(' ', '_', $package['name']) : '';
$documentName .= '_'.$idSupplier.'_'.$nameSuffix;
$sql = "
SELECT
d.documentName
FROM
".TABLES['documents']." d
INNER JOIN ".TABLES['rel_order_documents']." rod
ON d.id = rod.idDocument
WHERE rod.idOrder = $idOrder
AND rod.idPackage = $idPackage
AND d.idDocumentType = $idDocumentType
ORDER BY d.id DESC
LIMIT 1";
$lastDocName = $database->fetchResultArray($sql);
if($lastDocName && $lastDocName[0]['documentName']) {
$count = explode('_', $lastDocName[0]['documentName']);
$maxCount = intval(end($count)) + 1;
}
$documentName .= '_'.$maxCount;
$fileManager = new FileManager();
$data = $fileManager->uploadFile($file, $idDocumentType, $documentName, $supplier['idUser']);
if(isset($data['messages'])){
return $data;
}
$idDocument = $data['idDocument'];
$sql = "INSERT INTO ".TABLES['rel_order_documents']."
(idOrder, idPackage, idDocument, validation)
VALUES($idOrder, $idPackage, $idDocument, 'not-required')";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'FILE_UPLOADED'
];
}else{
$data['messages'][] = [
'code' => 'error',
'message' => 'NOT_UPLOADED'
];
}
return $data;
}
/**
* get scheduled dates for a step
* @param INT $idOrder id for the order
* @param INT $idPackage id for the package
* @param INT $idProcessStep id for the process step
* @return Array array of schedueld dates
*/
public function getScheduledDates($idOrder, $idPackage, $idProcessStep){
global $database;
$data = [];
$confirmations = $this->getUserConfirmationsForSchedules($idOrder, $idPackage, $idProcessStep);
$sql = "SELECT rosd.id AS idSchedule,
rosd.scheduledDate,
rosd.isDateConfirmed,
rosd.idProcessStep,
rosd.idPackage
FROM ".TABLES['rel_order_scheduled_dates']." rosd
WHERE rosd.idOrder=$idOrder AND rosd.idPackage=$idPackage AND rosd.idProcessStep=$idProcessStep
ORDER BY rosd.scheduledDate ASC ";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$row['confirmations'] = isset($confirmations[$row['idSchedule']]) ? $confirmations[$row['idSchedule']] : [];
$data[] = $row;
}
return $data;
}
/**
* get user confirimations for the scheduled dates
* @param INT $idOrder id for the order
* @param INT $idPackage id for the pakage
* @param INT $idProcessStep id for the process step
* @return Array list of confirmations
*/
private function getUserConfirmationsForSchedules($idOrder, $idPackage, $idProcessStep){
global $database;
$data = [];
$sql = "SELECT rosc.idSchedule,
rosc.status,
u.username,
ut.type AS userType
FROM ".TABLES['rel_order_schedules_confirmations']." rosc
INNER JOIN ".TABLES['rel_order_scheduled_dates']." rosd
ON rosc.idSchedule=rosd.id
INNER JOIN ".TABLES['users']." u
ON u.id=rosc.idUser
INNER JOIN ".TABLES['rel_user_type']." rut
ON rut.idUser=u.id
INNER JOIN ".TABLES['user_types']." ut
ON ut.id=rut.idType
WHERE rosd.idOrder=$idOrder AND rosd.idPackage=$idPackage AND rosd.idProcessStep=$idProcessStep";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['idSchedule']][] = $row;
}
return $data;
}
/**
* add users that need to confirm the schedule date for installation
* @param INT $idOrder id for the order
* @param INT $idSchedule id for the schedule
*/
private function addRequiredConfrimationUsers($idOrder, $idSchedule){
global $database;
$sql = "INSERT INTO ".TABLES['rel_order_schedules_confirmations']."
(idSchedule, idUser, status)
SELECT $idSchedule AS idSchedule,
c.idUser AS idUser,
'pending' AS status
FROM ".TABLES['orders']." o
INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id=o.idCUstomerInstance
INNER JOIN ".TABLES['customers']." c
ON c.id=rclc.idCustomer
WHERE o.id=$idOrder";
$query = $database->query($sql);
return $database->affectedRows();
}
/**
* Update the estimation date for the follow up meeting from an order
* @param Int $idOrder Id of the order to be modified
* @param Int $idProcessStep id of the porcess to be modified
* @param String $estimationDate new date to be added for a follow up meeting
* @param String $confirmedDate confirmed date with the customer to be added for a follow up meeting
* @return array response message for the update
*/
public function updateScheduledDates($idOrder, $idPackage, $idProcess, $idProcessStep, $idSchedule, $newDate) {
global $database;
$idOrder = $database->escapeValue($idOrder);
$idPackage = $database->escapeValue($idPackage);
$idProcess = $database->escapeValue($idProcess);
$idProcessStep = $database->escapeValue($idProcessStep);
$idSchedule = $database->escapeValue($idSchedule);
$newDate = $database->escapeValue($newDate);
$orderDetailsParams = [
'idOrder' => $idOrder,
'idPackage' => $idPackage,
'idProcess' => $idProcess
];
$data = [];
if($newDate !== '') {
$checkDate = $database->invalidDate('INVALID_DATE_ESTIMATED', $newDate);
if($checkDate){
$data['messages'][] = $checkDate;
return $data;
}
$newDate = "'$newDate'";
} else {
$newDate = "null";
}
if(intval($idSchedule) === 0){
$database->beginTransaction();
$sql = "
INSERT INTO ".TABLES['rel_order_scheduled_dates']." (
idOrder,
idPackage,
idProcessStep,
scheduledDate,
isDateConfirmed
)
VALUES(
$idOrder,
$idPackage,
$idProcessStep,
$newDate,
0
)";
$query = $database->query($sql);
$newIdSchedule = $database->getInsertId();
$affectedRows = $database->affectedRows();
$affectedRows += $this->addRequiredConfrimationUsers($idOrder, $newIdSchedule);
if($affectedRows > 0){
$database->commit();
}else{
$database->rollback();
$err_mes = [
'code' => 'error',
'message' => 'SERVER_ERROR'
];
$data['messages'][] = $err_mes;
return $data;
}
}else{
$sql = "UPDATE ".TABLES['rel_order_scheduled_dates']."
SET scheduledDate=$newDate
WHERE id=$idSchedule";
$query = $database->query($sql);
$affectedRows = $database->affectedRows();
}
if(!$query){
$err_mes = [
'code' => 'error',
'message' => 'SERVER_ERROR'
];
$data['messages'][] = $err_mes;
}
if($affectedRows > 0){
$sqlProcessStep = "
SELECT ps.shortDesc
FROM ".TABLES['process_step']." ps
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.idStep = ps.id
AND rps.id = $idProcessStep
LIMIT 1
";
$result = $database->fetchResultArray($sqlProcessStep);
$procStep = $result ? $result[0]['shortDesc'] : '';
/*if($estimationDate) {
$orderDetailsParams['estimatedMeetingDate'] = $estimationDate;
}
if($confirmedDate) {
$orderDetailsParams['confirmedMeetingDate'] = $confirmedDate;
}
$data['messages'][] = $this->sendConfirmationMail('scheduleMeeting', $orderDetailsParams);*/
$data['messages'][] = [
'code' => 'success',
'message' => 'ORDER_STEP_MEETING_DATE_UPDATED'
];
}
return $data;
}
/**
* update the status for an existing schedule date
* @param INT $idSchedule id for schedule date
* @param string $status new status for the schedule date
* @return Array update message
*/
public function updateScheduleDateStatus($idSchedule, $status, $idOrder, $idPackage, $actionCode){
global $database, $user;
$idSchedule = $database->escapeValue($idSchedule);
$data = [];
$sql = "UPDATE ".TABLES['rel_order_schedules_confirmations']."
SET status='$status'
WHERE idSchedule=$idSchedule AND idUser=".$user->getUserId();
$query = $database->query($sql);
if($database->affectedRows() > 0){
if($status === 'accepted' && $actionCode === 'choose-installation'){
$sql = "UPDATE ".TABLES['orders']."
SET acceptanceDueDate=DATE_ADD(
(SELECT scheduledDate
FROM ".TABLES['rel_order_scheduled_dates']."
WHERE id=$idSchedule),
INTERVAL 15 DAY)
WHERE id=$idOrder";
$query = $database->query($sql);
}
$updatedMainStatus = $this->updateScheduleGlobalStatus($idSchedule, $status);
$message = [
'code' => 'success',
'message' => 'SCHEDULE_STATUS_UPDATED'
];
$data['messages'][] = $message;
return $data;
}else{
$message = [
'code' => 'error',
'message' => 'SCHEDULE_STATUS_NOT_UPDATED'
];
$data['messages'][] = $message;
return $data;
}
}
/**
* update the status for the parent schedule date base on all users confirmation
* @param INT $idSchedule id for the scheduled date
* @param String $status new status addded to child
* @return INT number of affected rows
*/
private function updateScheduleGlobalStatus($idSchedule, $status){
global $database;
$confirmation = $status === 'accepted' ? 1 : -1;
$sql = "UPDATE ".TABLES['rel_order_scheduled_dates']."
SET isDateConfirmed=$confirmation
WHERE id=$idSchedule";
$query = $database->query($sql);
return $database->affectedRows();
}
/**
* get info for customer acceptance
* @param INT $idOrder id for the order
* @return Array custoemr acceptance info
*/
public function getCustomerAcceptance($idOrder){
global $database;
$idOrder = $database->escapeValue($idOrder);
$data = [];
$sql = "SELECT o.id AS idOrder,
o.customerAccepted,
IFNULL(o.customerDeclineReason, '') AS customerDeclineReason,
o.acceptanceDueDate
FROM ".TABLES['orders']." o
WHERE o.id=$idOrder";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$dueDate = new DateTime($row['acceptanceDueDate']);
$now = time();
$timeDiff = ($dueDate->getTimestamp() - $now ) / (3600 *24);
$row['daysDiff'] = $timeDiff;
$data[$row['idOrder']] = $row;
}
$sql = "SELECT
d.id AS idDocument,
d.documentName,
d.extension,
ro.idOrder
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['rel_order_documents']." ro
ON ro.idDocument=d.id
WHERE ro.idOrder=$idOrder AND d.idDocumentType=".self::DOCUMENT_TYPES['ID_ACCEPTANCE_DOC_TYPE'];
$query = $database->query($sql);
while($row = $database->fetchArray($query)) {
$data[$row['idOrder']]['acceptanceDocuments'][] = $row;
}
return $data;
}
/**
* upload customer acceptance document
* @param INT $idOrder id for the order
* @param INT $idPackage id for the packages
* @param FILE $file file to be uploaded
* @return Array upload status
*/
public function uploadAcceptanceDocument($idOrder, $idPackage, $file){
global $database, $user;
$idOrder = $database->escapeValue($idOrder);
$idPackage = $database->escapeValue($idPackage);
$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, self::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, idPackage, idDocument, validation)
VALUES($idOrder, $idPackage, $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;
}
/**
* get customer questionaires for a specific order
* @param INT $idOrder id for the order
* @param INT $idPackage id for the pacakge
* @param String $documentType the type of the documents needed - Order Questionaire or Installation protocol
* @return Array array of documents
*/
public function getOrderDocumentsPerType($idOrder, $idPackage, $documentType){
global $database, $user;
$idOrder = $database->escapeValue($idOrder);
$idPackage = $database->escapeValue($idPackage);
$documentType = $database->escapeValue($documentType);
$whereSql = $idPackage ? "AND rod.idPackage=$idPackage" : "";
$data = [];
if($documentType === 'orderQuestionaire') {
$idDocumentType = self::DOCUMENT_TYPES['ID_QUESTIONAIRE_DOC_TYPE'];
} else if($documentType === 'installationProtocol') {
$idDocumentType = self::DOCUMENT_TYPES['ID_INSTALLATION_PROTOTCOL_DOC_TYPE'];
} else {
return [];
}
$sql = "SELECT d.id AS idDocument,
d.uploadedBy,
d.documentName,
d.extension,
rod.validation
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['rel_order_documents']." rod
ON rod.idDocument=d.id
WHERE d.idDocumentType=$idDocumentType
AND rod.idOrder=$idOrder
$whereSql";
$query = $database->query($sql);
while($row = $database->fetchArray($query)) {
$row['isUploadedByMe'] = $user->getUserId() === $row['uploadedBy'];
unset($row['uploadedBy']);
$data[] = $row;
}
return $data;
}
/**
* checks if the next step enables the installation scheduling function
* @param Int $idOrder id of the order
* @param Array $stepIds the ids of the steps from which the scheduling function is enabled
* @return Bool true if the nest step is the one searched
*/
public function checkIfIsNextStepWanted($idOrder, $stepIds) {
global $database;
$idOrder = $database->escapeValue($idOrder);
$stepIds = (array) json_decode($stepIds);
$firstStepEnabled = $database->escapeValue($stepIds['firstStepEnabled']);
$lastStepEnabled = $database->escapeValue($stepIds['lastStepEnabled']);
$sql = "
SELECT
ps.id
FROM
".TABLES['rel_order_process_step']." rops
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.id = rops.idProcessStep
INNER JOIN process_step ps
ON ps.id = rps.idStep
AND ps.idActionCode=$firstStepEnabled
WHERE rops.idOrder = $idOrder
AND rops.status = 'inactive'
UNION ALL
SELECT
ps.id
FROM
".TABLES['rel_order_process_step']." rops
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.id = rops.idProcessStep
INNER JOIN ".TABLES['process_step']." ps
ON ps.id = rps.idStep
AND ps.idActionCode=$lastStepEnabled
WHERE rops.idOrder = $idOrder
AND (
rops.status = 'in-progress'
OR rops.status = 'done'
)";
$result = $database->query($sql);
return $database->numRows($result) > 0;
}
}

View File

@@ -0,0 +1,263 @@
<?php
class OrderHelper{
const DOCUMENT_TYPES = [
'ID_QUESTIONAIRE_DOC_TYPE' => 2, // 2 => 'orderQuestionaire'
'ID_CONFIGURATION_DOC_TYPE' => 3, // 3 => 'configuration'
'ID_ACCEPTANCE_DOC_TYPE' => 5, // 5 => 'customerAcceptance'
'ID_INSTALLATION_PROTOTCOL_DOC_TYPE' => 10 // 10 => 'installationProtocol'
];
/**
* 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 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 '';
}
/**
* gets the name of the customer and commercial lead by order id
* @param Int $idOrder the id of the order
* @return Array the names of the customer and commercial lead from the given order
*/
public function getCustomerAndCLNamesFromOrder($idOrder) {
global $database;
$sql = "
SELECT
c.name AS customerName,
cl.name AS commercialLeadName
FROM
".TABLES['orders']." o
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['commercial_leads']." cl
ON cl.id = rclc.idCommercialLead
WHERE o.id = $idOrder
LIMIT 1
";
$values = $database->fetchResultArray($sql);
return $values && $values[0] ? $values[0] : [];
}
/**
* returns the processId selected for a package in an order
* @param Int $idOrder id of the order
* @param Int $idPackage id of the package
* @return Int the id of the process selected
*/
public function getIdProcessSelectedForPackageOrder($idOrder, $idPackage) {
global $database;
if(!$idPackage) {
return 0;
}
$sql = "
SELECT
rps.idProcess
FROM
".TABLES['rel_process_steps']." rps
INNER JOIN ".TABLES['rel_order_process_step']." rops
ON rops.idProcessStep = rps.id
AND rops.idPackage = $idPackage
AND rops.idOrder = $idOrder
GROUP BY rps.idProcess
LIMIT 1
";
return $database->fetchResultArray($sql)[0]['idProcess'];
}
/**
* returns the mail addresses for cl and customer involved in the order process
* @param String $customerName customer's name
* @param String $commercialLeadName commercial lead's name
* @return Array mails of the customer and commercial lead
*/
public function getCLAndCustomerMails($customerName, $commercialLeadName, $isForComment = 0) {
global $database, $user;
$mailArray = [];
$sql = "
SELECT
c.idUser,
u.mail,
'customer' AS type
FROM
".TABLES['customers']." c
INNER JOIN ".TABLES['users']." u
ON u.id = c.idUser
WHERE c.name = '$customerName'
UNION
SELECT
cl.idUser,
u.mail,
'other' AS type
FROM
".TABLES['commercial_leads']." cl
INNER JOIN ".TABLES['users']." u
ON u.id = cl.idUser
WHERE cl.name = '$commercialLeadName'
";
$result = $database->query($sql);
while($row = $database->fetchArray($result)) {
if($row['mail'] !== '') {
if($isForComment) {
if($row['idUser'] != $user->getUserId()) {
$mailArray[$row['type']][] = $row['mail'];
}
} else {
$mailArray[$row['type']][] = $row['mail'];
}
}
}
return $mailArray;
}
/**
* check if user has rights to see a specific order
* @param INT $idOrder id of the order
* @return Boolean retruns true if the user can see the order
*/
public function checkOrderOwner($idOrder){
global $database, $user;
if($user->getUserType() === USER_TYPES['BROKER']){
return true;
}else if($user->getUserType() === USER_TYPES['CUSTOMER']){
$extraJoin = " INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id=o.idCustomerInstance
INNER JOIN ".TABLES['customers']." u
ON u.id=rclc.idCustomer";
}else if($user->getUserType() === USER_TYPES['COMMERCIAL_LEAD']){
$extraJoin = "INNER JOIN ".TABLES['rel_commercial_lead_customers']." rclc
ON rclc.id=o.idCustomerInstance
INNER JOIN ".TABLES['commercial_leads']." u
ON u.id=rclc.idCommercialLead";
}else if($user->getUserType() === USER_TYPES['SUPPLIER']){
$extraJoin = "INNER JOIN ".TABLES['rel_order_products_estimation']." rope
ON rope.idOrder=o.id
INNER JOIN ".TABLES['suppliers_countries_products']." scp
ON scp.idProduct=rope.idProduct
OR scp.idProductCategory = ".self::ID_INSTALLATION_CATEGORY."
INNER JOIN ".TABLES['suppliers']." u
ON u.id=scp.idSupplier";
}else{
return false;
}
$sql = "SELECT o.id
FROM ".TABLES['orders']." o
$extraJoin
WHERE u.idUser=".$user->getUserId()." AND o.id=$idOrder
LIMIT 1";
$query = $database->query($sql);
return $database->numRows($query) === 1;
}
/**
* upload document for an order
* @param Int $idOrder id of the order
* @param Int $idPackage id of the package
* @param Int $idFileType the id of the type of the file uploaded
* @param String $fileName the name of the file
* @param FILE $file file to be uploaded
* @return Array message with status
*/
public function uploadOrderDocument($idOrder, $idPackage, $idDocumentType, $documentName, $file){
global $database;
$idOrder = $database->escapeValue($idOrder);
$idPackage = $database->escapeValue($idPackage);
$idDocumentType = $database->escapeValue($idDocumentType);
$documentName = $database->escapeValue($documentName);
if(!$documentName){
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_NAME'
];
return $data;
}
if(!$idDocumentType){
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_TYPE'
];
return $data;
}
if(!$idPackage){
$data['messages'][] = [
'code' => 'error',
'message' => 'NO_PACKAGE'
];
return $data;
}
$sql = "SELECT d.id
FROM ".TABLES['documents']." d
WHERE d.documentName='$documentName'";
$query = $database->query($sql);
if($database->numRows($query) > 0){
$data['messages'][] = [
'code' => 'error',
'message' => 'NAME_EXISTS'
];
return $data;
}
$fileManager = new FileManager();
$data = $fileManager->uploadFile($file, $idDocumentType, $documentName);
if(isset($data['messages'])){
return $data;
}
if(array_search($idDocumentType, [self::DOCUMENT_TYPES['ID_CONFIGURATION_DOC_TYPE'], self::DOCUMENT_TYPES['ID_INSTALLATION_PROTOTCOL_DOC_TYPE']])) {
$docValidation = 'not-required';
} else {
$docValidation = 'not-validated';
}
$idDocument = $data['idDocument'];
$sql = "INSERT INTO ".TABLES['rel_order_documents']."
(idOrder, idPackage, idDocument, validation)
VALUES($idOrder, $idPackage, $idDocument, '$docValidation')";
$query = $database->query($sql);
$data['messages'][] = [
'code' => 'success',
'message' => 'DOCUMENT_UPLOADED'
];
return $data;
}
}

View File

@@ -0,0 +1,924 @@
<?php
class OrderProcessHelper {
/**
* insert new process step for order
* @param INT $idOrder id for order
* @param INT $idProcess id for process
* @return INT first step id or 0 on failure
*/
private function insertProcessStepsForOrder($idOrder, $idProcess){
global $database;
$sqlInsert = "INSERT IGNORE INTO ".TABLES['rel_order_process_step']."
(idProcessStep, idOrder, status)
VALUES ";
$sql = "SELECT rps.id AS idProcessStep,
rps.idParent,
$idOrder as idOrder,
CASE WHEN rps.idParent=0 THEN 'in-progress' ELSE 'inactive' END AS status
FROM ".TABLES['rel_process_steps']." rps
INNER JOIN
(
SELECT
rps_last.idProcess,
MAX(rps_last.processInstance) as lastInstace
FROM ".TABLES['rel_process_steps']." rps_last
WHERE rps_last.idProcess=$idProcess
GROUP BY rps_last.idProcess
) last_inst
ON last_inst.idProcess=rps.idProcess AND last_inst.lastInstace=rps.processInstance
INNER JOIN ".TABLES['process_step']." ps
ON ps.id=rps.idStep
WHERE rps.idProcess=$idProcess";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$sqlInsert .= "(
".$row['idProcessStep'].",
".$row['idOrder'].",
'".$row['status']."'),";
if(intval($row['idParent']) === 0){
$firstProcessStepId = $row['idProcessStep'];
}
}
$sqlInsert = rtrim($sqlInsert, ',');
$queryIns = $database->query($sqlInsert);
return $database->affectedRows() > 0 ? $firstProcessStepId : 0;
}
/**
* select a process for an order
* @param INT $idOrder id for the order
* @param INT $idProcess id for process
* @return Array update message
*/
public function setProcessForOrder($idOrder, $idProcess, $ordersDetailsMail){
global $database;
$data = [];
$actionsList = [];
$idOrder = $database->escapeValue($idOrder);
$idProcess = $database->escapeValue($idProcess);
$ordersDetailsMail = (array) json_decode($ordersDetailsMail);
$ordersDetailsMail['idProcess'] = $idProcess;
$orderActions = new OrderActions();
$firstStep = $this->insertProcessStepsForOrder($idOrder, $idProcess);
if($firstStep > 0){
$stepUpdated = $orderActions->executeAutomatedStep($idOrder, $firstStep);
if($stepUpdated > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'AUTOMATED_STEPS_EXECUTED'
];
$orderStatusUpdated = $this->updateOrderStatus($idOrder);
if($orderStatusUpdated['orderUpdated'] > 0) {
$message = [
'code' => 'success',
'message' => 'ORDER_UPDATED'
];
$data['messages'][] = $message;
$data['order'] = $orderStatusUpdated['orderUpdated'];
$ordersDetailsMail['status'] = $orderStatusUpdated['status'];
$data['messages'][] = $this->sendConfirmationMail('orderStatusChanged', $ordersDetailsMail);
}
$data['messages'][] = [
'code' => 'success',
'message' => 'PROCESS_SET'
];
$data['messages'][] = $this->sendConfirmationMail('processAssigned', $ordersDetailsMail);
}else{
$data['messages'][] = [
'code' => 'error',
'message' => 'AUTOMATED_STEPS_FAILED'
];
}
}else{
$data['messages'][] = [
'code' => 'error',
'message' => 'PROCESS_ADD_ERROR'
];
}
return $data;
}
/**
* get the order status
* @param HashArray $packageStatuses statuses for packages in order
* @return String order status
*/
private function getOrderStatusBasedOnPackages($packageStatuses){
$delivered = intval($packageStatuses['endOfLife']) + intval($packageStatuses['production']);
if($packageStatuses['endOfLife'] === $packageStatuses['totalPackages']){
return 'end-of-life';
}else if($delivered === intval($packageStatuses['totalPackages'])){
return 'production';
}else if($packageStatuses['processing'] > 0){
return 'in-progress';
}
return 'none';
}
/**
* update order status
* @param INT $idOrder id for order
* @return HashArray updated object
*/
public function updateOrderStatus($idOrder){
global $database;
$orderUpdated = 0;
$sqlStatuses = "SELECT
SUM(IF(rop.status = 'end-of-life', 1, 0)) as endOfLife,
SUM(IF(rop.status = 'processing', 1, 0)) as processing,
SUM(IF(rop.status ='production', 1, 0)) as production,
COUNT(rop.idPackage) as totalPackages
FROM ".TABLES['rel_order_packages']." rop
WHERE rop.idOrder=$idOrder
GROUP BY rop.idOrder";
$queryStatuses = $database->query($sqlStatuses);
$packageStatuses = $database->fetchArray($queryStatuses);
$status = $this->getOrderStatusBasedOnPackages($packageStatuses);
if($status === 'in-progress'){
$sqlUpdateOrder = "UPDATE ".TABLES['orders']."
SET status='$status'
WHERE id=$idOrder";
$query = $database->query($sqlUpdateOrder);
$orderUpdated = $database->affectedRows();
}else if($status === 'production' || $status === 'end-of-life'){
$deliveryDate = date("Y-m-d H:i:s");
$sqlUpdateOrder = "UPDATE ".TABLES['orders']."
SET status='$status',
deliveryDate=CASE WHEN deliveryDate IS NULL THEN '$deliveryDate' ELSE deliveryDate END
WHERE id=$idOrder";
$query = $database->query($sqlUpdateOrder);
$orderUpdated = $database->affectedRows();
}
return [
'orderUpdated' => $orderUpdated,
'status' => $status
];
}
/**
* get package and process names
* @param Int $idProcess the id of the process
* @param Int $idPackage the id of the package
* @return Array package and process names
*/
private function getProcessAndPackageName($idProcess, $idPackage) {
global $database;
if(!$idPackage){
return [];
}
$sql = "
SELECT
pack.name AS packageName,
proc.name AS processName
FROM
".TABLES['packages']." pack
INNER JOIN ".TABLES['processes']." proc
ON proc.id = $idProcess
WHERE pack.id = $idPackage";
return $database->fetchResultArray($sql)[0];
}
/**
* returns the previous and current process step for given order and package
* @param Int $idProcess id of the process
* @param Int $idPackage id of the package
* @param Int $idOrder id of the order
* @return Array array with current and previous steps of the order
*/
private function getPreviousAndCurrentSteps($idProcess, $idOrder) {
global $database;
$data = [
'currentStep' => '',
'prevStep' => ''
];
$sql = "
SELECT
ps.shortDesc,
rops.status
FROM
".TABLES['process_step']." ps
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.idStep = ps.id
INNER JOIN
(SELECT
MAX(processInstance) AS processInstance
FROM
".TABLES['rel_process_steps']."
WHERE idProcess = $idProcess) max_instance
ON rps.processInstance = max_instance.processInstance
INNER JOIN ".TABLES['rel_order_process_step']." rops
ON rops.idProcessStep = rps.id
AND rops.idOrder = $idOrder
AND rops.status = 'in-progress'
WHERE ps.isVisibleForCustomer = 1
UNION
SELECT
ps.shortDesc,
rops.status
FROM
".TABLES['process_step']." ps
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.idStep = ps.id
INNER JOIN
(SELECT
MAX(processInstance) AS processInstance
FROM
".TABLES['rel_process_steps']."
WHERE idProcess = $idProcess) max_instance
ON rps.processInstance = max_instance.processInstance
INNER JOIN ".TABLES['rel_order_process_step']." rops
ON rops.idProcessStep = rps.id
AND rops.idOrder = $idOrder
AND rops.status = 'done'
INNER JOIN
(SELECT
idParent
FROM
".TABLES['rel_process_steps']." rps_progress
INNER JOIN ".TABLES['rel_order_process_step']." rops_progress
ON rops_progress.idProcessStep = rps_progress.id
AND rops_progress.idOrder = $idOrder
AND rops_progress.status = 'in-progress') progress_parent
ON progress_parent.idParent = rps.id
WHERE ps.isVisibleForCustomer = 1
";
$result = $database->fetchResultArray($sql);
if(count($result) > 0) {
foreach($result as $stepDetails) {
if($stepDetails['status'] === 'in-progress') {
$data['currentStep'] = $stepDetails['shortDesc'];
}
if($stepDetails['status'] === 'done') {
$data['prevStep'] = $stepDetails['shortDesc'];
}
}
}
return $data;
}
/**
* returns the last process step for given order and package
* @param Int $idProcess id of the process
* @param Int $idOrder id of the order
* @return Array array with last step completed of the order
*/
private function getLastStepOrderCompleted($idProcess, $idOrder) {
global $database;
$data = [];
$sql = "
SELECT
ps.shortDesc AS shortDesc,
rops.status AS status,
ps.isVisibleForCustomer AS isVisibleForCustomer
FROM
".TABLES['process_step']." ps
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.idStep = ps.id
INNER JOIN
(SELECT
MAX(processInstance) AS processInstance,
MAX(id) AS id
FROM
".TABLES['rel_process_steps']."
WHERE idProcess = $idProcess) max_instance
ON rps.processInstance = max_instance.processInstance
AND rps.id = max_instance.id
INNER JOIN ".TABLES['rel_order_process_step']." rops
ON rops.idProcessStep = rps.id
AND rops.idOrder = $idOrder
AND rops.status = 'done'
";
$result = $database->fetchResultArray($sql);
if(count($result) > 0) {
$data['prevStep'] = [
'description' => $result[0]['shortDesc'],
'isVisibleForCustomer' => $result[0]['isVisibleForCustomer']
];
}
return $data;
}
/**
* checks parameters and sends mail based on the action made
* @param String $mailType the action for which to send the mail
* @param Json string $orderData the details regarding the order for which to send the mail
* @return Array confirmation message
*/
public function sendConfirmationMail($mailType, $orderData) {
global $database, $user;
$mailType = $database->escapeValue($mailType);
$orderHelper = new OrderHelper();
$commentMessage = array_key_exists('commentMessage', $orderData) ? $orderData['commentMessage'] : '';
foreach($orderData as $orderKey => $orderDetail) {
$orderData[$orderKey] = $database->escapeValue($orderDetail);
}
$data = [];
$idOrder = array_key_exists('idOrder', $orderData) ? $orderData['idOrder'] : 0;
$orderNumber = array_key_exists('orderNumber', $orderData) ? $orderData['orderNumber'] : $orderHelper->getOrderNumberById($idOrder);
if(!$mailType) {
return [
'code' => 'error',
'message' => 'ACTION_NOT_SET'
];
}
if(count($orderData) < 1) {
return [
'code' => 'error',
'message' => 'ORDER_DATA_NOT_SET'
];
}
if(!$idOrder) {
return [
'code' => 'error',
'message' => 'ID_ORDER_NOT_SET'
];
}
if(!$orderNumber) {
return [
'code' => 'error',
'message' => 'ORDER_NUMBER_NOT_SET'
];
}
if(!array_key_exists('customer', $orderData) || !array_key_exists('commercialLead', $orderData)) {
$customerCLNames = $orderHelper->getCustomerAndCLNamesFromOrder($idOrder);
$orderData['customer'] = $customerCLNames['customerName'];
$orderData['commercialLead'] = $customerCLNames['commercialLeadName'];
}
$idPackage = array_key_exists('idPackage', $orderData) ? $orderData['idPackage'] : 0;
$idProcess = array_key_exists('idProcess', $orderData) && $orderData['idProcess'] ? $orderData['idProcess'] : $orderHelper->getIdProcessSelectedForPackageOrder($idOrder, $idPackage);
$orderData['orderNumber'] = $orderNumber;
$names = $this->getProcessAndPackageName($idProcess, $idPackage);
$orderData['processName'] = array_key_exists('processName', $names) ? $names['processName'] : '';
$orderData['packageName'] = array_key_exists('packageName', $names) ? $names['packageName'] : '';
$currentDate = new DateTime();
$currentDate = $currentDate->format('d-m-Y H:i');
$params = [
'apiOrderUrl' => WIAAS_URL.'/api-wiaas/orders?subModule=orders_steps&idOrder='.$idOrder.'&orderNumber='.$orderNumber,
'orderUrl' => WIAAS_URL.'/orders/'.$idOrder,
'mailType' => $mailType,
'currentDate' => $currentDate,
'idOrder' => $idOrder,
'orderNumber' => $orderNumber,
'processName' => $orderData['processName'],
'packageName' => $orderData['packageName']
];
$mailAddresses = $orderHelper->getCLAndCustomerMails($orderData['customer'], $orderData['commercialLead']);
switch($mailType) {
case 'processAssigned':
$mailTitle = "Process assigned for order $orderNumber ($currentDate)";
break;
case 'orderStepUpdated':
$mailTitle = "Order $orderNumber updated ($currentDate)";
$steps = $this->getPreviousAndCurrentSteps($idProcess, $idOrder);
$params['currentStepMessage'] = $steps['currentStep'] ?
"<b>".$steps['currentStep']."</b> is currently in progress.<br />" :
'';
$params['prevStepMessage'] = $steps['prevStep'] ?
"The step <b>".$steps['prevStep']."</b> has been completed successfully.<br />" :
'';
break;
case 'lastStepCompleted':
$mailTitle = "Order $orderNumber is successfully completed ($currentDate)";
$lastStep = $this->getLastStepOrderCompleted($idProcess, $idOrder);
$params['prevStepMessage'] = $lastStep['prevStep']['isVisibleForCustomer'] === '1' ?
"The step <b>".$lastStep['prevStep']['description']."</b> has been done.<br />" :
'';
break;
case 'packageStatusChanged':
$mailTitle = "Order's $orderNumber package status updated ($currentDate)";
$params['status'] = $orderData['status'];
$params['deliveryEstimationDateMessage'] = array_key_exists('estimatedDate', $orderData) ?
"The estimated date to complete the step is <b>".$orderData['estimatedDate']."</b>. <br />" :
'';
break;
case 'scheduleMeeting':
$mailTitle = "Follow-up meeting date updated for order $orderNumber ($currentDate)";
$mailAddresses = $orderHelper->getCLAndCustomerMails($orderData['customer'], $orderData['commercialLead'], 1);
$params['estimatedDateMessage'] = array_key_exists('estimatedMeetingDate', $orderData) ?
"The estimated date set for the follow-up meeting is <b>".$orderData['estimatedMeetingDate']."</b>. <br />" :
'';
$params['confirmedDateMessage'] = array_key_exists('confirmedMeetingDate', $orderData) ?
"The confimed date set for the follow-up meeting is <b>".$orderData['confirmedMeetingDate']."</b>. <br />" :
'';
break;
case 'orderStatusChanged':
$mailTitle = "Order $orderNumber changed it's status to ".$orderData['status']. " ($currentDate)";
$params['status'] = $orderData['status'];
$params['deliveryEstimationDateMessage'] = array_key_exists('estimatedDate', $orderData) ?
"The estimated delivery date for the order is <b>".$orderData['estimatedDate']."</b>. <br />" :
'';
break;
case 'orderCommentAdded':
if(array_key_exists('isStepComment', $orderData)) {
$mailTitle = "New comment for step in order $orderNumber ($currentDate)";
$mailAddresses = $orderHelper->getCLAndCustomerMails('', $orderData['commercialLead'], 1);
} else {
$mailTitle = "New comment for order $orderNumber ($currentDate)";
$mailAddresses = $orderHelper->getCLAndCustomerMails($orderData['customer'], $orderData['commercialLead'], 1);
}
$params['commentMessage'] = $commentMessage;
$params['userLoggedIn'] = $user->getUserFullName();
break;
default:
return $data;
}
return UtilsModel::sendOrderUpdateMail($mailType, $params, $mailTitle, $mailAddresses);
}
/**
* get comments for all oreder steps
* @param INT $idOrder id of the order
* @return Array list of comments for an order grouped by idPackage and idProcessStep
*/
private function getStepsComments($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.comment,
rsc.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']);
$comments[$idProcessStep][] = $row;
}
return $comments;
}
/**
* 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 = '';
$orderHelper = new OrderHelper();
if(!$orderHelper->checkOrderOwner($idOrder)){
return [];
}
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";
}
$comments = $this->getStepsComments($idOrder);
$sql = "SELECT o.id AS idOrder,
ps.shortDesc,
ps.fullDesc,
ps.isVisibleForCustomer,
psa.actionCode,
psa.stepType,
rops.idProcessStep,
rops.status,
rops.actualDate,
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
";
$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;
}
/**
* Update the actual date for an order
* @param Int $idOrder Id of the order to be modified
* @param Int $idProcessStep id of the porcess to be modified
* @param String $actualDate new date to be added for an order actual date step completed
* @return array resopnese message for the update
*/
public function updateStepActualDate($idOrder, $idProcessStep, $actualDate, $ordersDetailsMail) {
global $database;
$data = [];
$idOrder = $database->escapeValue($idOrder);
$idProcessStep = $database->escapeValue($idProcessStep);
$actualDate = $database->escapeValue($actualDate);
$ordersDetailsMail = (array) json_decode($ordersDetailsMail);
$orderProcessHelper = new OrderProcessHelper();
$checkDate = $database->invalidDate('ACTUAL_DATE_INCORRECT', $actualDate);
if($checkDate){
$data['messages'][] = $checkDate;
return $data;
}
$sql = "UPDATE ".TABLES['rel_order_process_step']."
SET actualDate='$actualDate'
WHERE idOrder=$idOrder AND idProcessStep=$idProcessStep
LIMIT 1";
$query = $database->query($sql);
if(!$query){
$err_mes = [
'code' => 'error',
'message' => 'SERVER_ERROR'
];
$data['messages'][] = $err_mes;
}
if($database->affectedRows() === 1){
$message = [
'code' => 'success',
'message' => 'ORDER_STEP_ACTUAL_DATE_UPDATED'
];
$data['messages'][] = $message;
$sqlProcessStep = "
SELECT ps.shortDesc
FROM ".TABLES['process_step']." ps
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.idStep = ps.id
AND rps.id = $idProcessStep
LIMIT 1
";
$result = $database->fetchResultArray($sqlProcessStep);
$procStep = $result ? $result[0]['shortDesc'] : '';
$ordersDetailsMail['status'] = 'actual date set for step "'.$procStep.'"';
$ordersDetailsMail['actualDate'] = $actualDate;
$data['messages'][] = $orderProcessHelper->sendConfirmationMail('packageStatusChanged', $ordersDetailsMail);
}
return $data;
}
/**
* update commnet for a step
* @param int $idOrder id of the order
* @param int $idProcessStep process step id
* @param String $comment comment
* @return arary messages array
*/
public function updateStepComment($idOrder, $idProcessStep, $comment, $isVisible, $ordersDetailsMail) {
global $database, $user;
$data = [];
$idOrder = $database->escapeValue($idOrder);
$idProcessStep = $database->escapeValue($idProcessStep);
$comment = $database->escapeValue($comment);
$isVisible = $database->escapeValue($isVisible);
$idUser = $user->getUserId();
$ordersDetailsMail = (array) json_decode($ordersDetailsMail);
$orderProcessHelper = new OrderProcessHelper();
$checkMessage = $database->invalidLength('COMMENT_LONG',$comment, 700);
if($checkMessage){
$data['messages'][] = $checkMessage;
return $data;
}
$sql = "INSERT INTO ".TABLES['rel_step_comments']."
(idProcessStep, idOrder, idUser, comment, isVisible)
VALUES ($idProcessStep, $idOrder, $idUser, '$comment', $isVisible)";
$query = $database->query($sql);
if(!$query){
$err_mes = [
'code' => 'error',
'message' => 'SERVER_ERROR'
];
$data['messages'][] = $err_mes;
}
if($database->affectedRows() === 1){
$message = [
'code' => 'success',
'message' => 'ORDER_STEP_COMMENT_UPDATED'
];
$data['messages'][] = $message;
if($isVisible) {
$ordersDetailsMail['commentMessage'] = $comment;
$ordersDetailsMail['isStepComment'] = true;
$data['messages'][] = $orderProcessHelper->sendConfirmationMail('orderCommentAdded', $ordersDetailsMail);
}
}
return $data;
}
/**
* update the visibility for a comment
* @param INT $idComment id of the comment
* @param boolean $isVisible visibility for the step
* @return Array update message
*/
public function updateStepCommentVisibility($idComment, $isVisible){
global $database;
$data = [];
$idComment = $database->escapeValue($idComment);
$isVisible = $database->escapeValue($isVisible);
$sql = "UPDATE ".TABLES['rel_step_comments']."
SET isVisible=$isVisible
WHERE id=$idComment
LIMIT 1";
$query = $database->query($sql);
if(!$query){
$err_mes = [
'code' => 'error',
'message' => 'SERVER_ERROR'
];
$data['messages'][] = $err_mes;
}
if($database->affectedRows() === 1){
$message = [
'code' => 'success',
'message' => 'ORDER_STEP_COMMENT_UPDATED'
];
$data['messages'][] = $message;
}
return $data;
}
private function updateOrderPackagseStatus($idOrder){
global $database;
$packageUpdated = 0;
$sqlRemaningSteps = "SELECT COUNT(rops.idProcessStep) as remainingSteps
FROM ".TABLES['rel_order_process_step']." rops
WHERE rops.idOrder=$idOrder and rops.status!='done'";
$queryRemaining = $database->query($sqlRemaningSteps);
$rowsRemaining = $database->fetchArray($queryRemaining);
if(intval($rowsRemaining['remainingSteps']) === 0){
$sqlPayTerm = "SELECT pt.packagePayPeriod,
pt.servicesContractPeriod
FROM ".TABLES['payment_types']." pt
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rop.idPaymentTerm=pt.id
WHERE rop.idOrder=$idOrder
LIMIT 1";
$queryPayTerm = $database->query($sqlPayTerm);
while($payTerm = $database->fetchArray($queryPayTerm)){
$packagePayTerm = intval($payTerm['packagePayPeriod'], 10);
$servicesPayTerm = intval($payTerm['servicesContractPeriod'], 10);
$maxPeriod = max($packagePayTerm, $servicesPayTerm);
$deliveryDate = date("Y-m-d H:i:s");
$status = 'production';
$endOfLife = "DATE_ADD('$deliveryDate', INTERVAL $maxPeriod MONTH)";
$sql = "UPDATE ".TABLES['rel_order_packages']."
SET status='$status', endOfLife=$endOfLife
WHERE idOrder=$idOrder";
$query = $database->query($sql);
$packageUpdated = $database->affectedRows($query);
}
}
return $packageUpdated;
}
public function goToNextStep($idOrder, $idProcessStep, $ordersDetailsMail){
global $database;
$idOrder = $database->escapeValue($idOrder);
$idProcessStep = $database->escapeValue($idProcessStep);
$ordersDetailsMail = (array) json_decode($ordersDetailsMail);
$orderProcessHelper = new OrderProcessHelper();
$orderActions = new OrderActions();
$err_mes = [
'code' => 'error',
'message' => 'SERVER_ERROR'
];
$data['messages'][] = $err_mes;
$childSteps = $orderActions->getStepChilds($idProcessStep);
$stepsStatusUpdated = $orderActions->updateActiveStep($idOrder, $idProcessStep, $childSteps);
//in case automated steps are available code goes here
if($stepsStatusUpdated > 0){
$data['messages'][0] = [
'code' => 'success',
'message' => 'ACTIVE_STEP_UPDATE'
];
$data['messages'][] = [
'code' => 'success',
'message' => 'NEW_STEP_ACTIVATED'
];
$data['updated_active'] = $stepsStatusUpdated;
if(empty($childSteps)) {
$data['messages'][] = $orderProcessHelper->sendConfirmationMail('lastStepCompleted', $ordersDetailsMail);
} else {
$data['messages'][] = $orderProcessHelper->sendConfirmationMail('orderStepUpdated', $ordersDetailsMail);
}
}
$packageStatusUpdated = $this->updateOrderPackagseStatus($idOrder);
$orderStatusUpdated = $orderProcessHelper->updateOrderStatus($idOrder);
if($orderStatusUpdated['orderUpdated'] > 0) {
$message = [
'code' => 'success',
'message' => 'ORDER_UPDATED'
];
$data['messages'][] = $message;
$data['order'] = $orderStatusUpdated['orderUpdated'];
$data['sendMail'] = [
'message' => 'orderStatusChanged',
'status' => $orderStatusUpdated['status']
];
}
return $data;
}
/**
* undo a step
* @param INT $idOrder id for the order
* @param INT $idProcessStep id for the process step
* @return Array update message
*/
public function undoStep($idOrder, $idProcessStep){
$orderActions = new OrderActions();
$stepsStatusUpdated = $orderActions->undoStep($idOrder, $idProcessStep);
if($stepsStatusUpdated > 0){
$data['messages'][0] = [
'code' => 'success',
'message' => 'ACTIVE_STEP_UNDONE'
];
$customerInfo = UtilsModel::getDataForMailToCustomer($idOrder);
$currentDate = new DateTime();
$currentDate = $currentDate->format('d-m-Y H:i');
$stepDetails = $this->getProcessStepDetailsById($idProcessStep);
if(array_key_exists('isVisibleForCustomer', $stepDetails) && intval($stepDetails['isVisibleForCustomer']) === 1) {
$params = [
'orderUrl' => WIAAS_URL.'/orders/'.$idOrder,
'orderNumber' => $customerInfo['orderNumber'],
'processStepName' => $stepDetails['shortDesc'],
'currentDate' => $currentDate
];
$response = Mail::sendMail($customerInfo['mail'], 'Process step reopened', 'undoStepTemplate.php', $params);
if($response){
$data['messages'][] = [
'code' => 'success',
'message' => 'ORDER_UPDATE_MAIL_SENT'
];
} else {
$data['messages'][] = [
'code' => 'error',
'message' => 'ERROR_MAIL_SENT'
];
}
}
}else{
$err_mes = [
'code' => 'error',
'message' => 'SERVER_ERROR'
];
$data['messages'][] = $err_mes;
}
return $data;
}
/**
* get process step name and if is visible to customer based on the id
* @param INT $idProcessStep the id of the process step
* @return String the name of the process step
*/
public function getProcessStepDetailsById($idProcessStep) {
global $database;
$sqlProcessStep = "SELECT
ps.shortDesc,
ps.isVisibleForCustomer
FROM
".TABLES['process_step']." ps
INNER JOIN ".TABLES['rel_process_steps']." rps
ON rps.idStep = ps.id
INNER JOIN
(SELECT
idParent
FROM
".TABLES['rel_process_steps']."
WHERE id = $idProcessStep) parentProcess
ON rps.id = parentProcess.idParent
LIMIT 1";
$result = $database->fetchResultArray($sqlProcessStep);
return $result && $result[0] ? $result[0] : [];
}
}

View File

@@ -0,0 +1,121 @@
<?php
class OrderTraking{
/**
* add tracking number and url for order/package/supplier
* @param INT $idOrder id for the order
* @param INT $idSupplier id for the supplier
* @param String $trackingNumber traking id
* @param String $trackingUrl traking url
* @return Array update message
*/
public function addTracking($idOrder, $idSupplier, $trackingNumber, $trackingUrl) {
global $database;
$idOrder = $database->escapeValue($idOrder);
$idSupplier = $database->escapeValue($idSupplier);
$trackingNumber = $database->escapeValue($trackingNumber);
$trackingUrl = $database->escapeValue($trackingUrl);
$data = [];
if (filter_var($trackingUrl, FILTER_VALIDATE_URL) === FALSE) {
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_URL'
];
return $data;
}
$sql = "INSERT INTO ".TABLES['rel_order_supplier_options']." (
idOrder,
idSupplier,
trackingNumber,
trackingUrl
)
VALUES
($idOrder, $idSupplier, '$trackingNumber', '$trackingUrl')";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'TRAKING_ID_ADDED'
];
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}
return $data;
}
/**
* update dates for products in an order
* @param INT $idTracking id for the tracking info
* @param String $trackingNumber traking id
* @param String $trackingUrl traking url
* @return Array update message
*/
public function updateTracking($idTracking, $trackingNumber, $trackingUrl){
global $database;
$idTracking = $database->escapeValue($idTracking);
$trackingNumber = $database->escapeValue($trackingNumber);
$trackingUrl = $database->escapeValue($trackingUrl);
$data = [];
if (filter_var($trackingUrl, FILTER_VALIDATE_URL) === FALSE) {
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_URL'
];
return $data;
}
$sql = "UPDATE ".TABLES['rel_order_supplier_options']."
SET trackingNumber='$trackingNumber',
trackingUrl='$trackingUrl'
WHERE id=$idTracking";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'TRAKING_ID_UPDATED'
];
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}
return $data;
}
public function removeTracking($idTracking) {
global $database;
$idTracking = $database->escapeValue($idTracking);
$data = [];
$sql = "DELETE FROM ".TABLES['rel_order_supplier_options']." WHERE id=$idTracking";
$result = $database->query($sql);
if($database->affectedRows()){
$data['messages'][] = [
'code' => 'success',
'message' => 'TRACKING_REMOVED'
];
} else {
$data['messages'][] = [
'code' => 'error',
'message' => 'TRACKING_REMOVED_ERROR'
];
}
return $data;
}
}

View File

@@ -0,0 +1,664 @@
<?php
/**
* OrdersController controls the actions for orders
*/
class OrdersController{
private $model;
function __construct(){
$this->model = new OrdersModel();
}
/**
* returns json array with table headers for orders
* @return list all columns headers
*/
public function getOngoingOrdersHeaders(){
echo json_encode($this->model->getOngoingOrdersHeaders('array'));
}
/**
* returns json response for orders
* @return list prders json
*/
public function getOngoingOrders(){
$data = ['data' => $this->model->getOngoingOrders()];
echo json_encode($data);
}
/**
* returns json array with table headers for orders history
* @return list all columns headers
*/
public function getOrdersHistoryHeaders(){
echo json_encode($this->model->getOrdersHistoryHeaders('array'));
}
/**
* returns json response for orders history
* @return list prders json
*/
public function getOrdersHistory(){
$data = ['data' => $this->model->getOrdersHistory()];
echo json_encode($data);
}
/**
* 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));
}
/**
* returns json with steps for a specific order
* @return array order steps
*/
public function getOrderSteps() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
echo json_encode($this->model->getOrderSteps($idOrder));
}
/**
* change step for orders
* @return json result of the update
*/
public function goToNextStep() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
$ordersDetailsMail = isset($_REQUEST['ordersDetailsMail']) ? $_REQUEST['ordersDetailsMail'] : '[]';
echo json_encode($this->model->goToNextStep($idOrder, $idProcessStep, $ordersDetailsMail));
}
/**
* undo step for orders
* @return json result of the update
*/
public function undoStep() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
echo json_encode($this->model->undoStep($idOrder, $idProcessStep));
}
/**
* update the estimation for an order
* @return json json message for update result
*/
public function updateOrderEstimation() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$estimationDate = isset($_REQUEST['estimationDate']) ? $_REQUEST['estimationDate'] : '';
echo json_encode($this->model->updateOrderEstimation($idOrder, $estimationDate));
}
/**
* update the end of life date for a package and change order status if required
* @return json message for update result
*/
public function updatePackageEndOfLife(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$endOfLife = isset($_REQUEST['endOfLife']) ? $_REQUEST['endOfLife'] : '';
$ordersDetailsMail = isset($_REQUEST['ordersDetailsMail']) ? $_REQUEST['ordersDetailsMail'] : '[]';
echo json_encode($this->model->updatePackageEndOfLife($idOrder, $idPackage, $endOfLife, $ordersDetailsMail));
}
/**
* update the estimation for an order step
* @return json json message for update result
*/
public function updateScheduledDates() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idProcess = isset($_REQUEST['idProcess']) ? $_REQUEST['idProcess'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
$idSchedule = isset($_REQUEST['idSchedule']) ? $_REQUEST['idSchedule'] : 0;
$newDate = isset($_REQUEST['newDate']) ? $_REQUEST['newDate'] : '';
echo json_encode($this->model->updateScheduledDates($idOrder, $idPackage, $idProcess, $idProcessStep, $idSchedule, $newDate));
}
/**
* update the status for an existing schedule date
* @return json update message
*/
public function updateScheduleDateStatus(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$actionCode = isset($_REQUEST['actionCode']) ? $_REQUEST['actionCode'] : '';
$idSchedule = isset($_REQUEST['idSchedule']) ? $_REQUEST['idSchedule'] : 0;
$status = isset($_REQUEST['status']) ? $_REQUEST['status'] : '';
echo json_encode($this->model->updateScheduleDateStatus($idSchedule, $status, $idOrder, $idPackage, $actionCode));
}
/**
* get scheduled dates for a step
* @return json list of scheduled dates
*/
public function getScheduledDates(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
echo json_encode($this->model->getScheduledDates($idOrder, $idPackage, $idProcessStep));
}
/**
* update the actual date for an order step
* @return json message for update result
*/
public function updateStepActualDate() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
$actualDate = isset($_REQUEST['actualDate']) ? $_REQUEST['actualDate'] : '';
$ordersDetailsMail = isset($_REQUEST['ordersDetailsMail']) ? $_REQUEST['ordersDetailsMail'] : '[]';
echo json_encode($this->model->updateStepActualDate($idOrder, $idProcessStep, $actualDate, $ordersDetailsMail));
}
/**
* update comment for an order
* @return json update message
*/
public function updateOrderComment() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : null;
$ordersDetailsMail = isset($_REQUEST['ordersDetailsMail']) ? $_REQUEST['ordersDetailsMail'] : '[]';
echo json_encode($this->model->updateOrderComment($idOrder, $comment, $ordersDetailsMail));
}
/**
* update commnets for an order
* @return json json message for update result
*/
public function updateStepComment() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
$comment = isset($_REQUEST['comment']) ? $_REQUEST['comment'] : null;
$isVisible = isset($_REQUEST['isVisible']) ? intval($_REQUEST['isVisible']) : 0;
$ordersDetailsMail = isset($_REQUEST['ordersDetailsMail']) ? $_REQUEST['ordersDetailsMail'] : '[]';
echo json_encode($this->model->updateStepComment($idOrder, $idProcessStep, $comment, $isVisible, $ordersDetailsMail));
}
/**
* cancel one order
* @return json json message for cancel result
*/
public function cancelOrder() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$ordersDetailsMail = isset($_REQUEST['ordersDetailsMail']) ? $_REQUEST['ordersDetailsMail'] : '[]';
echo json_encode($this->model->cancelOrder($idOrder, $ordersDetailsMail));
}
/**
* set a selected process for an orders package
* @return json update message
*/
public function setProcessForOrder(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idProcess = isset($_REQUEST['idProcess']) ? $_REQUEST['idProcess'] : 0;
$ordersDetailsMail = isset($_REQUEST['ordersDetailsMail']) ? $_REQUEST['ordersDetailsMail'] : '[]';
echo json_encode($this->model->setProcessForOrder($idOrder, $idProcess, $ordersDetailsMail));
}
public function assignBroker(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idBroker = isset($_REQUEST['idBroker']) ? $_REQUEST['idBroker'] : 0;
echo json_encode($this->model->assignBroker($idOrder, $idBroker));
}
/**
* update visibility for a comment
* @return json update message
*/
public function updateStepCommentVisibility(){
$idComment = isset($_REQUEST['idComment']) ? $_REQUEST['idComment'] : 0;
$isVisible = isset($_REQUEST['isVisible']) ? intval($_REQUEST['isVisible']) : 0;
echo json_encode($this->model->updateStepCommentVisibility($idComment, $isVisible));
}
/**
* gets the system allowed languages from the DB
* @return json array with allowed languages in the system
*/
public function getSystemAllowedLanguages() {
echo json_encode($this->model->getSystemAllowedLanguages());
}
/**
* get brokers list
* @return json list of brokers
*/
public function getBrokers(){
echo json_encode($this->model->getBrokers());
}
/**
* update status for packages and orders in case of end of life
* @return text update message for statuses
*/
public function updateOrdersEndOfLife(){
echo $this->model->updateOrdersEndOfLife();
}
/**
* genereate file for procurement report
* @return file file for procurement report
*/
public function generateProcurementExcel(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$this->model->generateProcurementExcel($idOrder);
}
/**
* gets all thge installation companies for the order and package selected
* @return Array with the installation companies
*/
public function getInstallCompaniesForPackage() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->getInstallCompaniesForPackage($idOrder, $idPackage));
}
/**
* save installation company for order and package
* @return Array with confirmation messages
*/
public function saveInstallationCompany() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idInstallation = isset($_REQUEST['idInstallation']) ? $_REQUEST['idInstallation'] : 0;
echo json_encode($this->model->saveInstallationCompany($idOrder, $idPackage, $idInstallation));
}
/**
* get customer questionnaires documents
* @return json list of documents
*/
public function getOrderDocumentsPerType(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$documentType = isset($_REQUEST['documentType']) ? $_REQUEST['documentType'] : '';
echo json_encode($this->model->getOrderDocumentsPerType($idOrder, $idPackage, $documentType));
}
/**
* update status for a questionnaire
* @return json update message
*/
public function validateQuestionaire(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idDocument = isset($_REQUEST['idDocument']) ? $_REQUEST['idDocument'] : 0;
$idProcessStep = isset($_REQUEST['idProcessStep']) ? $_REQUEST['idProcessStep'] : 0;
$validationStatus = isset($_REQUEST['validationStatus']) ? $_REQUEST['validationStatus'] : '';
$invalidQuestionaireReason = isset($_REQUEST['invalidQuestionaireReason']) ? $_REQUEST['invalidQuestionaireReason'] : '';
echo json_encode($this->model->validateQuestionaire($idOrder, $idPackage, $idDocument, $idProcessStep, $validationStatus, $invalidQuestionaireReason));
}
/**
* 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));
}
/**
* get estimation and confirmation dates for products
* @return json list of dates for products in procurement step
*/
public function getSupplierEstimations(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
echo json_encode($this->model->getSupplierEstimations($idOrder));
}
/**
* update date values for products in an order (procurement step)
* @return json update message
*/
public function updateSupplierEstimation(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idSupplier = isset($_REQUEST['idSupplier']) ? $_REQUEST['idSupplier'] : 0;
$estimatedDate = isset($_REQUEST['estimatedDate']) ? $_REQUEST['estimatedDate'] : '';
$confirmedDate = isset($_REQUEST['confirmedDate']) ? $_REQUEST['confirmedDate'] : '';
echo json_encode($this->model->updateSupplierEstimation($idOrder, $idSupplier, $estimatedDate, $confirmedDate));
}
/**
* remove estimation or confirm date
* @return json update message
*/
public function removeSupplierEstimation(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idSupplier = isset($_REQUEST['idSupplier']) ? $_REQUEST['idSupplier'] : 0;
$type = isset($_REQUEST['type']) ? $_REQUEST['type'] : '';
echo json_encode($this->model->removeSupplierEstimation($idOrder, $idSupplier, $type));
}
/**
* adds traking info
* @return json update message
*/
public function addTracking(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idSupplier = isset($_REQUEST['idSupplier']) ? $_REQUEST['idSupplier'] : 0;
$trackingNumber = isset($_REQUEST['trackingNumber']) ? $_REQUEST['trackingNumber'] : '';
$trackingUrl = isset($_REQUEST['trackingUrl']) ? $_REQUEST['trackingUrl'] : '';
echo json_encode($this->model->addTracking($idOrder, $idSupplier, $trackingNumber, $trackingUrl));
}
/**
* update traking id
* @return json update message
*/
public function updateTracking(){
$idTracking = isset($_REQUEST['idTracking']) ? $_REQUEST['idTracking'] : 0;
$trackingNumber = isset($_REQUEST['trackingNumber']) ? $_REQUEST['trackingNumber'] : '';
$trackingUrl = isset($_REQUEST['trackingUrl']) ? $_REQUEST['trackingUrl'] : '';
echo json_encode($this->model->updateTracking($idTracking, $trackingNumber, $trackingUrl));
}
/**
* delete traking information
* @return json update message
*/
public function removeTracking() {
$idTracking = isset($_REQUEST['idTracking']) ? $_REQUEST['idTracking'] : 0;
echo json_encode($this->model->removeTracking($idTracking));
}
/**
* upload required files for suppliers (configuration or installation)
* @return json upload message
*/
public function uploadConfigurationDocument(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
$idSupplier = isset($_REQUEST['idSupplier']) ? $_REQUEST['idSupplier'] : 0;
$fileType = isset($_REQUEST['fileType']) ? $_REQUEST['fileType'] : '';
echo json_encode($this->model->uploadConfigurationDocument($idOrder, $idPackage, $idSupplier, $fileType, $file));
}
/**
* upload required files for suppliers (configuration or installation)
* @return json upload message
*/
public function uploadInstallationDocument(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
$idSupplier = isset($_REQUEST['idSupplier']) ? $_REQUEST['idSupplier'] : 0;
$fileType = isset($_REQUEST['fileType']) ? $_REQUEST['fileType'] : '';
echo json_encode($this->model->uploadConfigurationDocument($idOrder, $idPackage, $idSupplier, $fileType, $file));
}
public function getInstallationDocuments() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->getInstallationDocuments($idOrder, $idPackage));
}
public function getCustomerAcceptance(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
echo json_encode($this->model->getCustomerAcceptance($idOrder));
}
public function uploadAcceptanceDocument(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
echo json_encode($this->model->uploadAcceptanceDocument($idOrder, $idPackage, $file));
}
/**
* customer change acceptance status for a package
* @return Array message confirmation
*/
public function acceptDeclineInstallation(){
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$actionType = isset($_REQUEST['actionType']) ? $_REQUEST['actionType'] : '';
$declineReason = isset($_REQUEST['declineReason']) ? $_REQUEST['declineReason'] : '';
echo json_encode($this->model->acceptDeclineInstallation($idOrder, $idPackage, $actionType, $declineReason));
}
/**
* get availability if send support mail button is visible
* @return boolean value if send mail is available or not
*/
public function getAvailabilityForSendSupportMail() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
echo json_encode($this->model->getAvailabilityForSendSupportMail($idOrder));
}
/**
* sends a mail to the support team
* @return json confirmation message
*/
public function sendSupportMail() {
$ordersInfo = isset($_REQUEST['ordersInfo']) ? $_REQUEST['ordersInfo'] : '[]';
$orderPackages = isset($_REQUEST['orderPackages']) ? $_REQUEST['orderPackages'] : '[]';
$userText = isset($_REQUEST['userText']) ? $_REQUEST['userText'] : '';
echo json_encode($this->model->sendSupportMail($ordersInfo, $orderPackages, $userText));
}
/**
* 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));
}
/**
* returns the suppliers for order
* @return json array with suppliers
*/
public function getSuppliersByPackageOrder() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$documentType = isset($_REQUEST['documentType']) ? $_REQUEST['documentType'] : '';
echo json_encode($this->model->getSuppliersByPackageOrder($idOrder, $idPackage, $documentType));
}
/**
* removes the document wanted
* @return json array with confirmation messages
*/
public function removeOrderDocument() {
$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->removeOrderDocument($idOrder, $idPackage, $idDocument));
}
/**
* sets the earliest installation
* @return json array with id order and package
*/
public function setEarliestInstallationDateInDb() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$maxDeliveryDate = isset($_REQUEST['maxDeliveryDate']) ? $_REQUEST['maxDeliveryDate'] : '';
echo json_encode($this->model->setEarliestInstallationDateInDb($idOrder, $idPackage, $maxDeliveryDate));
}
/**
* returns the earliest installation date based on the maximum delivery date plus the additional days
* @return json array with earliest installation date
*/
public function getEarliestInstallationDate() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->getEarliestInstallationDate($idOrder, $idPackage));
}
/**
* 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));
}
public function checkIfDateAlreadyAccepted() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
echo json_encode($this->model->checkIfDateAlreadyAccepted($idOrder, $idPackage));
}
/**
* 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));
}
/**
* returns a bool value if it is the step we are searching for
* @return boolean value with confirmation if it's what we want
*/
public function checkIfIsNextStepWanted() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$stepIds = isset($_REQUEST['stepIds']) ? $_REQUEST['stepIds'] : '[]';
echo json_encode($this->model->checkIfIsNextStepWanted($idOrder, $stepIds));
}
/**
* upload a document for order and per package
* @return json array with update messages
*/
public function uploadOrderDocument() {
$idOrder = isset($_REQUEST['idOrder']) ? $_REQUEST['idOrder'] : 0;
$idPackage = isset($_REQUEST['idPackage']) ? $_REQUEST['idPackage'] : 0;
$idDocumentType = isset($_REQUEST['idDocumentType']) ? $_REQUEST['idDocumentType'] : 0;
$fileName = isset($_REQUEST['fileName']) ? $_REQUEST['fileName'] : '';
$file = isset($_FILES['file']) ? $_FILES['file'] : [];
echo json_encode($this->model->uploadOrderDocument($idOrder, $idPackage, $idDocumentType, $fileName, $file));
}
/**
* gives template for updating orders
* @return json json for orers updatemodel like for webshop
*/
public function updateOrdersJson(){
require_once('orders_update_template/orders_update_template.json');
}
/**
* include orders template
*/
public function ordersTemplate() {
global $user;
require_once('templates/OrdersTemplate.php');
}
/**
* include orders ongoing details template
*/
public function ordersDetailsTemplate() {
global $user;
require_once('templates/OrdersDetailsTemplate.php');
}
/**
* incldes template for orders steps
*/
public function changeOrdersStepsTemplate() {
global $user;
require_once('templates/ChangeOrdersStepsTemplate.php');
}
/**
* includes template for assign broker
*/
public function assignBrokerTemplate() {
require_once('templates/AssignBrokerTemplate.html');
}
/**
* includes template for components procurement extra action
*/
public function procurementTemplate() {
global $user;
require_once('templates/extra-actions/procurementTemplate.php');
}
/**
* includes template for choosing installation company extra action
*/
public function chooseInstallationTemplate() {
global $user;
require_once('templates/extra-actions/chooseInstallationTemplate.php');
}
/**
* includes template for scheduling follow up meeting extra action
*/
public function scheduleMeetingTemplate() {
global $user;
require_once('templates/extra-actions/scheduleMeetingTemplate.php');
}
/**
* includes template for validate questionnaire extra action
*/
public function validateQuestionnaireTemplate(){
global $user;
require_once('templates/extra-actions/validateQuestionnaireTemplate.php');
}
public function suppliersProcurementViewTemplate(){
global $user;
require_once('templates/SuppliersProcurementViewTemplate.php');
}
/**
* includes template for customer acceptance extra action
*/
public function customerAcceptanceTemplate(){
global $user;
require_once('templates/extra-actions/customerAcceptanceTemplate.php');
}
/**
* includes template for the email to the support team
*/
public function supportMailTemplate() {
require_once('templates/SupportMailTemplate.html');
}
/**
* open orders page
*/
public function showPage() {
require_once('OrdersPage.php');
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,22 @@
<script src="<?php echo PATH_JS_COMPONENTS.'orders/orders-details.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/orders.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/change-orders-steps.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/suppliers-procurement-view.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/assign-broker.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/support-mail.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/orders-utils.service.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/set-delivery-dates.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/installation-scheduler.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/upload-documents-for-order-package.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/extra-actions/procurement.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/extra-actions/choose-installation.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/extra-actions/validate-questionnaire.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/extra-actions/schedule-meeting.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orders/extra-actions/customer-acceptance.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orderProjects/order-projects.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<script src="<?php echo PATH_JS_COMPONENTS.'orderProjects/order-projects-edit.directive.js?v='.APPLICATION_VERSION;?>" type="text/javascript"></script>
<div id="orders-module" class="container-fluid col-md-12">
<h1>{{ 'orders.TITLE' | translate }}</h1>
<orders ng-controller="ordersController"></orders>
</div>

View File

@@ -0,0 +1,88 @@
<?php
class Procurement{
/**
* get documents grouped by suppliers
* @param INT $idOrder id for the order
* @param String $documentType the type of the document
* @return Array list of documents
*/
private function getSupplierDocuments($idOrder, $documentType = ''){
global $database;
$data = [];
$extraWhere = '';
if($documentType) {
$extraWhere = "
AND d.idDocumentType =
(SELECT
dt.id
FROM
document_types dt
WHERE dt.folderName = '$documentType')";
}
$sql = "SELECT d.id as idDocument,
d.documentName,
d.extension,
rod.idPackage,
s.name AS supplierName
FROM ".TABLES['documents']." d
INNER JOIN ".TABLES['rel_order_documents']." rod
ON rod.idDocument=d.id
INNER JOIN ".TABLES['suppliers']." s
ON s.idUser=d.idOwner
WHERE rod.idOrder=$idOrder $extraWhere";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['supplierName']][] = $row;
}
return $data;
}
/**
* get suppliers products
* @param INT $idOrder id for the order
* @param INT $idPackage id for the order
* @param String $documentType the type of the document
* @return Array Array of products estimations
*/
public function getSuppliersByPackageOrder($idOrder, $idPackage, $documentType){
global $database, $user;
$supplierBidsHandler = new SupplierBids();
$idOrder = $database->escapeValue($idOrder);
$idPackage = $database->escapeValue($idPackage);
$documentType = $database->escapeValue($documentType);
$data = [];
$whereSql = "";
$documents = $this->getSupplierDocuments($idOrder, $documentType);
$supplierBids = $supplierBidsHandler->getOrderSupplierBids($idOrder);
if($user->getUserType() === USER_TYPES['SUPPLIER']){
$whereSql .= " AND s.idUser=".$user->getUserId();
}
if($idPackage != 0){
$whereSql .= " AND idPackage=$idPackage";
}
$sql = "SELECT s.id AS idSupplier,
s.name AS supplierName
FROM ".TABLES['rel_order_supplier_estimations']." rose
INNER JOIN ".TABLES['suppliers']." s
ON s.id=rose.idSupplier
WHERE idOrder=$idOrder $whereSql
ORDER BY s.id";
$query = $database->query($sql);
while($row = $database->fetchArray($query)){
$data[$row['supplierName']]['idSupplier'] = $row['idSupplier'];
$data[$row['supplierName']]['documents'] = isset($documents[$row['supplierName']]) ? $documents[$row['supplierName']] : [];
$data[$row['supplierName']]['supplierBids'] = isset($supplierBids[$row['idSupplier']]) ? $supplierBids[$row['idSupplier']] : [];
}
return $data;
}
}

View File

@@ -0,0 +1,258 @@
<?php
class SupplierEstimations{
private function getTrackingInfo($idOrder) {
global $database;
$data = [];
$sql = "
SELECT
roso.id AS idTracking,
roso.idSupplier,
roso.trackingNumber,
roso.trackingUrl
FROM
".TABLES['rel_order_supplier_options']." roso
WHERE roso.idOrder = $idOrder";
$query = $database->query($sql);
while($row = $database->fetchArray($query)) {
$data[$row['idSupplier']][] = $row;
}
return $data;
}
/**
* add null values for products estimations in an order
* @param INT $idOrder id of the order
*/
private function addStartEstimatisonForProducts($idOrder){
global $database;
$sql = "INSERT INTO ".TABLES['rel_order_supplier_estimations']."
(idOrder, idSupplier)
SELECT rop.idOrder, scp.idSupplier
FROM ".TABLES['rel_package_products']." rpp
INNER JOIN ".TABLES['rel_order_packages']." rop
ON rop.idPackage=rpp.idPackage AND rop.packageInstance=rpp.packageInstance
INNER JOIN ".TABLES['suppliers_countries_products']." scp
ON scp.idProduct=rpp.idProduct
WHERE rop.idOrder=$idOrder
GROUP BY rop.idOrder, scp.idSupplier";
$query = $database->query($sql);
return $database->affectedRows();
}
/**
* get estimations for products
* @param INT $idOrder id for the order
* @return Array Array of products estimations
*/
public function getSupplierEstimations($idOrder){
global $database, $user;
$idOrder = $database->escapeValue($idOrder);
$data = [];
$whereSql = "";
$trackingInfo = $this->getTrackingInfo($idOrder);
if($user->getUserType() === USER_TYPES['SUPPLIER']){
$whereSql = " AND s.idUser=".$user->getUserId();
}
$sql = "SELECT
rose.estimatedDate,
rose.confirmedDate,
s.id AS idSupplier,
s.name AS supplierName
FROM ".TABLES['rel_order_supplier_estimations']." rose
INNER JOIN ".TABLES['suppliers']." s
ON s.id=rose.idSupplier
WHERE idOrder=$idOrder $whereSql
ORDER BY s.id";
$query = $database->query($sql);
if($database->numRows($query) === 0){
if($user->getUserType() === USER_TYPES['SUPPLIER']) {
return $data;
}
$addedStartValues = $this->addStartEstimatisonForProducts($idOrder);
if($addedStartValues > 0){
return $this->getSupplierEstimations($idOrder);
}else{
return $data;
}
}
while($row = $database->fetchArray($query)){
$row['trackings'] = isset($trackingInfo[$row['idSupplier']]) ? $trackingInfo[$row['idSupplier']] : [];
$data[] = $row;
}
return $data;
}
private function isProductOwner($idSupplier){
global $user, $database;
if($user->getUserType() === USER_TYPES['BROKER']){
return true;
}else if($user->getUserType() === USER_TYPES['SUPPLIER']){
$sql = "SELECT s.id
FROM ".TABLES['suppliers']." s
WHERE s.id=$idSupplier AND s.idUser=".$user->getUserId();
$query = $database->query($sql);
return $database->numRows($query) > 0;
}
return false;
}
/**
* update dates for products in an order
* @param INT $idOrder id for the order
* @param INT $idSupplier od for the supplier
* @param String $estimatedDate estimated date
* @param String $confirmedDate confirmed date
* @return Array update message
*/
public function updateSupplierEstimation($idOrder, $idSupplier,$estimatedDate, $confirmedDate){
global $database;
$idOrder = $database->escapeValue($idOrder);
$idSupplier = $database->escapeValue($idSupplier);
$estimatedDate = $database->escapeValue($estimatedDate);
$confirmedDate = $database->escapeValue($confirmedDate);
$data = [];
if(!$this->isProductOwner($idSupplier)){
$data['messages'][] = [
'code' => 'error',
'message' => 'NOT_OWNER_OF_PROD'
];
return $data;
}
if(!$idOrder || !$idSupplier){
$data['messages'][] = [
'code' => 'error',
'message' => 'EST_MISSING_DATA'
];
return $data;
}
if(empty($estimatedDate) && empty($confirmedDate)){
$data['messages'][] = [
'code' => 'error',
'message' => 'EMPTY_DATES'
];
return $data;
}
$checkEstimatedDate = $database->invalidDate('INVALID_DATE_ESTIMATED', $estimatedDate);
$checkConfirmedDate = $database->invalidDate('INVALID_DATE_ESTIMATED', $confirmedDate);
if(($checkEstimatedDate && !empty($estimatedDate)) || ($checkConfirmedDate && !empty($confirmedDate))){
$data['messages'][] = $checkEstimatedDate ? $checkEstimatedDate : [];
$data['messages'][] = $checkConfirmedDate ? $checkConfirmedDate : [];
return $data;
}
if(empty($estimatedDate)){
$estimatedDate = $confirmedDate;
}
$estimatedDate = !empty($estimatedDate) ? "'$estimatedDate'" : "null";
$confirmedDate = !empty($confirmedDate) ? "'$confirmedDate'" : "null";
$sql = "UPDATE ".TABLES['rel_order_supplier_estimations']."
SET estimatedDate=$estimatedDate,
confirmedDate=$confirmedDate
WHERE idOrder=$idOrder AND idSupplier=$idSupplier";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'SUPPLIER_ESTIMATION_UPDATED'
];
$data['idSupplier'] = $idSupplier;
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}
return $data;
}
/**
* update dates for products in an order
* @param INT $idOrder id for the order
* @param INT $idSupplier id for the package
* @param String $type estiamtion or confirmation date
* @return Array update message
*/
public function removeSupplierEstimation($idOrder, $idSupplier, $type){
global $database;
$idOrder = $database->escapeValue($idOrder);
$idSupplier = $database->escapeValue($idSupplier);
$type = $database->escapeValue($type);
$data = [];
if(!$this->isProductOwner($idSupplier)){
$data['messages'][] = [
'code' => 'error',
'message' => 'NOT_OWNER_OF_PROD'
];
return $data;
}
if(!$idOrder || !$idSupplier){
$data['messages'][] = [
'code' => 'error',
'message' => 'EST_MISSING_DATA'
];
return $data;
}
if($type !== 'estimation' && $type !== 'confirmation'){
$data['messages'][] = [
'code' => 'error',
'message' => 'INVALID_ESTIMATION_TYPE'
];
return $data;
}
$fieldToUpdate = $type === 'estimation' ? "estimatedDate=NULL" : "confirmedDate=NULL";
$sql = "UPDATE ".TABLES['rel_order_supplier_estimations']."
SET $fieldToUpdate
WHERE idOrder=$idOrder AND idSupplier=$idSupplier";
$query = $database->query($sql);
if($database->affectedRows() > 0){
$data['messages'][] = [
'code' => 'success',
'message' => 'SUPPLIER_ESTIMATION_UPDATED'
];
}else{
$data['messages'][] = [
'code' => 'warning',
'message' => 'NO_CHANGES'
];
}
return $data;
}
}

View File

@@ -0,0 +1,47 @@
<div id="add-documents-to-order-container" ng-controller="uploadDocumentsForOrderPackageCtrl" ng-init="getDocumentTypes()">
<span ng-if="isOrderOngoingOrCompleted()" class="col-md-5 outside-process-steps">
<h3 class="upload-files-header">{{'orders.tables.headers.uploadFile' | translate}}</h3>
<hr />
<form id="upload-new-doc-container" name="form" class="row">
<div class="col-md-6">
<div class="document-types">
<label>{{'orders.headers.DOCUMENT_TYPES' | translate}}: </label>
<select id="document-types-for-order"
class="form-control-static add-document-value"
ng-model="docType"
ng-options="docType.type for docType in documentTypes track by docType.idDocumentType"
ng-change="selectFileType(docType)">
<option value="" disabled selected>{{'orders.headers.SELECT_DOCUMENT_TYPE' | translate}}</option>
</select>
</div>
<div class="document-types">
<label>{{'orders.headers.PACKAGES' | translate}}: </label>
<select id="document-packages-for-order"
class="form-control-static add-document-value"
ng-model="package"
ng-options="package.packageName for package in packages track by package.idPackage"
ng-change="selectPackage(package)">
<option value="" disabled selected>{{'orders.headers.SELECT_PACKAGE' | translate}}</option>
</select>
</div>
<div class="document-types">
<label>{{'orders.headers.DOCUMENT_NAME' | translate}}: </label>
<input id="new-doc-name"
class="add-document-value"
type="text"
placeholder="{{'orders.headers.DOCUMENT_NAME' | translate}}"
ng-model="$parent.fileName" />
</div>
</div>
<div class="col-md-6">
<div ngf-drop="uploadFile($file)"
ng-model="files"
ngf-drag-over-class="'dragover'"
ngf-select="uploadFile($file)"
ngf-pattern="'.pdf,.docx,.doc,.xlsx,.xls,.odt,.ods,.png,.jpg,.jpeg'"
ngf-max-size="20MB"
class="drop-box">{{'orders.headers.SELECT_DOCUMENT' | translate}}</div>
</div>
</form>
</span>
</div>

View File

@@ -0,0 +1,9 @@
<div ng-if="isOrderOngoing(ordersInfo.status)" id="assign-broker-parent" class="col-md-2">
<label class="order-label">{{'orders.tables.headers.assignedTo' | translate}}</label>
<div class="order-box">
<div class="assign-broker-layer" id-order="{{ordersInfo.id}}">
<div class="assigned-broker">{{ordersInfo.assignedTo}}</div>
<div id="enalbe-assign-edit" ng-init="enableAssignBrokerEdit()" class="assign-icon glyphicon glyphicon-pencil"></div>
</div>
</div>
</div>

Some files were not shown because too many files have changed in this diff Show More