dbutils = new DbUtils(); $this->queue = new QueueContent(); $this->commonUtils = new CommonUtils(); $this->userrights = new Userrights(); } public function createSqlPhrases() { self::$sql_service_good = "select COUNT(service) as count FROM %ratings% WHERE service='1' AND date between ? AND ?"; self::$sql_service_ok = "select COUNT(service) as count FROM %ratings% WHERE service='2' AND date between ? AND ?"; self::$sql_service_bad = "select COUNT(service) as count FROM %ratings% WHERE service='3' AND date between ? AND ?"; self::$sql_kitchen_good = "select COUNT(kitchen) as count FROM %ratings% WHERE kitchen='1' AND date between ? AND ?"; self::$sql_kitchen_ok = "select COUNT(kitchen) as count FROM %ratings% WHERE kitchen='2' AND date between ? AND ?"; self::$sql_kitchen_bad = "select COUNT(kitchen) as count FROM %ratings% WHERE kitchen='3' AND date between ? AND ?"; self::$sql_ratings = "select COUNT(id) as count FROM %ratings% WHERE date between ? AND ?"; self::$sql_remarks = "SELECT DATE_FORMAT(date, '%e.%m.%Y %H:%i') AS date,remark FROM %ratings% WHERE CHAR_LENGTH(remark) > 2 AND date between ? AND ?"; } function handleCommand($command) { header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0"); header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); // canUserCallCommands($currentCmd, $cmdArray,$right) $cmdArray = array('getStats'); if (in_array($command, $cmdArray)) { if (!($this->userrights->hasCurrentUserRight('right_statistics'))) { echo "Benutzerrechte nicht ausreichend!"; return false; } } $this->createSqlPhrases(); $allDates = self::getDates(); $pdo = DbUtils::openDbAndReturnPdoStatic(); switch($command) { case 'getStats': $this->getStats($pdo); break; case 'getUsersums': $values = $this->getUsersums($pdo); echo json_encode(array("status" => "OK","msg" => $values)); break; case 'getToday': $values = $this->iterateForHours($pdo, $allDates['todayDate'], intval($allDates['todayHour'])+1,false); echo json_encode(array("status" => "OK","msg" => $values)); break; case 'getYesterday': $values = $this->iterateForHours($pdo, $allDates['yesterdayDate'], 24,true); echo json_encode(array("status" => "OK","msg" => $values)); break; case 'getThismonth': $values = $this->iterateForDays($pdo, $allDates['monthAndYearOfThisMonth'],intval($allDates['currentDay']),true); echo json_encode(array("status" => "OK","msg" => $values)); break; case 'getLastmonth': $values = $this->iterateForDays($pdo, $allDates['monthAndYearOfLastMonth'],intval($allDates['lastDayOfLastMonth']),true); echo json_encode(array("status" => "OK","msg" => $values)); break; case 'getProds': $values = $this->sumSortedByProducts($pdo, $allDates['last30days'][0], $allDates['currentTimeStr']); echo json_encode(array("status" => "OK","msg" => $values)); break; case 'getRatings': $values = $this->getRatings($pdo,$allDates['last30days'],$allDates['lastMonthComplete'], $allDates['currentTimeStr']); echo json_encode(array("status" => "OK","msg" => $values)); break; case 'getMonthNames': echo json_encode(array("status" => "OK","thismonth" => $allDates['thisMonthName'],"lastmonth" => $allDates['lastMonthName'])); break; default: echo "Command not supported."; } } private function getStats($pdo = null) { if (is_null($pdo)) { $pdo = DbUtils::openDbAndReturnPdoStatic(); } $this->createSqlPhrases(); $alldates = self::getDates(); $this->getReports($pdo,$alldates); } public function getStatsCore($pdo,$forDash = false) { $this->createSqlPhrases(); $alldates = self::getDates(); return($this->getReportsCore($pdo,$alldates,$forDash)); } static private function getDates() { date_default_timezone_set(DbUtils::getTimeZone()); $currentTimeStr = date('Y-m-d H:i:s'); $curTime = strtotime($currentTimeStr); $todayDate = date('Y-m-d'); $todayHour = date('H'); $yesterdayDate = date("Y-m-d", strtotime("-1 day", $curTime)); // now for this month $firstDayOfThisMonth = date("Y-m-01", strtotime($currentTimeStr)); $currentDay = date("d",strtotime($currentTimeStr)); // current day (4 if date is 4 Jan 2014) $month = date("m",strtotime($currentTimeStr)); $monthName = self::getMonthName($month); $monthAndYearOfThisMonth = date("Y-m",strtotime($currentTimeStr)); $thisMonthName = self::getMonthName($month); // last month $last_month_ini = new DateTime("first day of last month"); $last_month_end = new DateTime("last day of last month"); $firstDayOfLastMonth = $last_month_ini->format('Y-m-d'); $lastDayOfLastMonth = $last_month_end-> format('d'); $iterations = intval($last_month_end->format('d')); $lastMonth = intval($last_month_ini->format('m')); $monthAndYearOfLastMonth = $last_month_end->format('Y-m'); $lastMonthComplete = $last_month_ini->format('Y-m-d') . " 00:00:00"; $lastMonthName = self::getMonthName($lastMonth); // last 30 days $daysArr = array(); for ($i=29;$i>=0;$i--) { $daysArr[] = date("Y-m-d", strtotime('-' . $i . ' day') ); } $retArray = array( "todayDate" => $todayDate, "todayHour" => $todayHour, "currentTimeStr" => $currentTimeStr, "yesterdayDate" => $yesterdayDate, "monthAndYearOfLastMonth" => $monthAndYearOfLastMonth, "lastDayOfLastMonth" => $lastDayOfLastMonth, "lastMonthComplete" => $lastMonthComplete, "lastMonthName" => $lastMonthName, "currentDay" => $currentDay, "monthAndYearOfThisMonth" => $monthAndYearOfThisMonth, "thisMonthName" => $thisMonthName, "last30days" => $daysArr ); return $retArray; } public static function getMonthName($monthNo) { $mons = array( 1 => "Januar", 2 => "Februar", 3 => "März", 4 => "April", 5 => "Mai", 6 => "Juni", 7 => "Juli", 8 => "August", 9 => "September", 10 => "Oktober", 11 => "November", 12 => "Dezember"); return ($mons[intval($monthNo)]); } private function getReports ($pdo,$allDates) { $reports = $this->getReportsCore($pdo,$allDates); echo json_encode($reports); } private function getReportsCore($pdo,$allDates,$forDash = false) { $pdo->beginTransaction(); // bills of today independently of closing $retArrayToday = $this->iterateForHours($pdo, $allDates['todayDate'], intval($allDates['todayHour'])+1,false); // closed yesterday bills: $retArrayYesterday = $this->iterateForHours($pdo, $allDates['yesterdayDate'], 24,true); $retThisMonth = $this->iterateForDays($pdo, $allDates['monthAndYearOfThisMonth'],intval($allDates['currentDay']),true); // closed of last month: $retArrayLastMonth = $this->iterateForDays($pdo, $allDates['monthAndYearOfLastMonth'],intval($allDates['lastDayOfLastMonth']),true); // products in the last 30 days: $retArrayProds = $this->sumSortedByProducts($pdo, $allDates['last30days'][0], $allDates['currentTimeStr']); $retRatings = $this->getRatings($pdo,$allDates['last30days'],$allDates['lastMonthComplete'], $allDates['currentTimeStr']); $usersums = $this->getUserSums($pdo); $pdo->commit(); $retArray = array("today" => $retArrayToday, "yesterday" => $retArrayYesterday, "thismonth" => $retThisMonth, "lastmonth" => $retArrayLastMonth, "prodsums" => $retArrayProds, "lastmonthname" => $allDates['lastMonthName'], "thismonthname" => $allDates['thisMonthName'], "ratings" => $retRatings, "usersums" => $usersums ); if ($forDash) { $retArray["tables"] = self::getOpenTables($pdo); $retArray["prodscount"] = self::getMaxSoldProductsCount($pdo); $retArray["prodssum"] = self::getMaxSoldProductsSum($pdo); $retArray["durations"] = self::getGuestDuration($pdo); } return $retArray; } /* * returns an array: * hour, sum * hour, sum */ private function iterateForHours($pdo,$theDateStr,$noOfIterations,$mustBeClosed) { $retArray = array(); $sumMax = 0.0; for ($i=0;$i<$noOfIterations;$i++) { $startDateTime = $theDateStr . " $i:00:00"; $endDateTime = $theDateStr . " $i:59:59"; $sum = $this->sumBetween($pdo,$startDateTime,$endDateTime,$mustBeClosed); if ($sumMax < $sum) { $sumMax = $sum; } $retArray[] = array("iter" => $i, "sum" => $sum); } return array("max" => $sumMax, "content" => $retArray); } /* * returns an array wioth "content" * day, sum with day 0..31, * day, sum ... */ private function iterateForDays($pdo,$theMonthYearStr,$noOfIterations,$mustBeClosed) { $retArray = array(); $sumMax = 0.0; for ($i=1;$i<($noOfIterations+1);$i++) { $dayInTwoDigists = sprintf('%02d', $i); $startDateTime = $theMonthYearStr . "-$dayInTwoDigists 00:00:00"; $endDateTime = $theMonthYearStr . "-$dayInTwoDigists 23:59:59"; $sum = $this->sumBetween($pdo,$startDateTime,$endDateTime,$mustBeClosed); if ($sumMax < $sum) { $sumMax = $sum; } $retArray[] = array("iter" => $i, "sum" => $sum); } return array("max" => $sumMax, "content" => $retArray); } private function sumBetween($pdo,$startDateTime,$endDateTime,$mustBeClosed) { $sql = "SELECT sum(brutto) as sumtotal FROM %bill% "; $sql .= "WHERE status is null "; // no cash insert or take off, no stornos $sql .= "AND billdate between ? AND ? "; if ($mustBeClosed) { $sql .= "AND closingid is not null"; // and must be in a closing } $sum = 0.0; $stmt = $pdo->prepare($this->dbutils->resolveTablenamesInSqlString($sql)); $stmt->execute(array($startDateTime,$endDateTime)); $row =$stmt->fetchObject(); if ($row != null) { $theSqlSum = $row->sumtotal; if ($theSqlSum != null) { $sum = $theSqlSum; } } return $sum; } function cmp($a, $b) { $asum = $a['sum']; $bsum = $b['sum']; if ($asum == $bsum) { return 0; } return ($asum < $bsum) ? 1 : -1; } /* * returns a sorted by prices list: * array("prodid" => $aProdId,"prodname" => $aProd['prodname'], "sum" => $sumprice); * array("prodid" => $aProdId,"prodname" => $aProd['prodname'], "sum" => $sumprice); * (...) */ public function sumSortedByProducts($pdo,$startDateTime,$endDateTime,$closidstart=null,$closidend=null) { // first get all products and with their id and name if (is_null($closidstart)) { $sql = "SELECT DISTINCT productid from %queue%,%bill%,%products% "; $sql .= "WHERE %queue%.productid=%products%.id "; $sql .= "AND billid is not null AND %queue%.billid=%bill%.id "; $sql .= "AND billdate between ? AND ? "; $sql .= "AND %bill%.closingid is not null "; $sql .= "AND %bill%.status is null"; $result = CommonUtils::fetchSqlAll($pdo, $sql, array($startDateTime,$endDateTime)); } else { $sql = "SELECT DISTINCT productid from %queue% Q,%bill% B,%products% P "; $sql .= "WHERE Q.productid=P.id "; $sql .= "AND billid is not null AND Q.billid=B.id "; $sql .= "AND B.closingid is not null "; $sql .= "AND B.closingid between ? AND ? "; $sql .= "AND B.status is null"; $result = CommonUtils::fetchSqlAll($pdo, $sql, array($closidstart,$closidend)); } $prods = array(); $sql = "SELECT longname FROM %products% WHERE id=?"; $stmt = $pdo->prepare(DbUtils::substTableAlias($sql)); foreach($result as $aProd) { $stmt->execute(array($aProd["productid"])); $row = $stmt->fetchObject(); $prods[] = array("prodid" => $aProd['productid'],"prodname" => $row->longname); } // now iterate over all prods $sumMax = 0.0; $prodinfos = array(); foreach ($prods as $aProd) { $aProdId = $aProd['prodid']; if (is_null($closidstart)) { $sql = "SELECT sum(price) as sumprice, count(%queue%.id) as prodcount from %queue%,%bill%,%products% "; $sql .= "WHERE %queue%.productid=%products%.id "; $sql .= "AND billid is not null AND %queue%.billid=%bill%.id "; $sql .= "AND billdate between ? AND ? "; $sql .= "AND %bill%.closingid is not null "; $sql .= "AND productid=?"; $stmt = $pdo->prepare($this->dbutils->resolveTablenamesInSqlString($sql)); $stmt->execute(array($startDateTime,$endDateTime,$aProdId)); $row =$stmt->fetchObject(); } else { $sql = "SELECT sum(price) as sumprice, count(%queue%.id) as prodcount from %queue%,%bill%,%products% "; $sql .= "WHERE %queue%.productid=%products%.id "; $sql .= "AND billid is not null AND %queue%.billid=%bill%.id "; $sql .= "AND %bill%.closingid is not null "; $sql .= "AND %bill%.closingid between ? AND ? "; $sql .= "AND productid=?"; $stmt = $pdo->prepare($this->dbutils->resolveTablenamesInSqlString($sql)); $stmt->execute(array($closidstart,$closidend,$aProdId)); $row =$stmt->fetchObject(); } if ($row != null) { $sumprice = $row->sumprice; if ($sumMax < $sumprice) { $sumMax = $sumprice; } if ($sumprice != null) { $prodinfo = $aProd['prodname'] . " (" . $row->prodcount . "x)"; $prodinfos[] = array("prodid" => $aProdId,"iter" => $prodinfo, "sum" => $sumprice); } } } uasort($prodinfos, array($this,'cmp')); // due to a bug somehow the order is not kept when transformed to json - copy... $prodInfoSorted = array(); foreach($prodinfos as $prodinfo) { $prodInfoSorted[] = array("iter" => $prodinfo['iter'],"sum" => $prodinfo['sum']); } return array("max" => $sumMax, "content" => $prodInfoSorted); } static function getRating($pdo,$sql,$start,$end) { $stmt = $pdo->prepare(DbUtils::substTableAlias($sql)); $stmt->execute(array($start,$end)); $row =$stmt->fetchObject(); if (!is_null($row)) { return(intval($row->count)); } else { return 0; } } static function getRelation($val1,$val2,$val3,$maxPercent) { $total = $val1 + $val2 + $val3; if ($total == 0) { return array (0.0,0.0,0.0,$maxPercent); } else { $rel = $maxPercent / ((double)$total); return array($rel * $val1,$rel * $val2,$rel * $val3,0.0); } } static function getRatingOfDay($pdo,$aDay,$start,$end) { $serviceGood = self::getRating($pdo,self::$sql_service_good, $start, $end); $serviceOK = self::getRating($pdo,self::$sql_service_ok, $start, $end); $serviceBad = self::getRating($pdo,self::$sql_service_bad, $start, $end); $serviceRel = self::getRelation($serviceGood,$serviceOK,$serviceBad,95); $kitchenGood = self::getRating($pdo,self::$sql_kitchen_good, $start, $end); $kitchenOK = self::getRating($pdo,self::$sql_kitchen_ok, $start, $end); $kitchenBad = self::getRating($pdo,self::$sql_kitchen_bad, $start, $end); $kitchenRel = self::getRelation($kitchenGood,$kitchenOK,$kitchenBad,95); $totalRatings = self::getRating($pdo,self::$sql_ratings, $start, $end); $date = new DateTime($aDay); return array("day" => $date->format('d.m.Y'), "service" => $serviceRel, "kitchen" => $kitchenRel, "total" => $totalRatings); } function getRatings($pdo,$last30days,$startPeriod,$endPeriod){ $reports = array(); foreach($last30days as $aDay) { $start = $aDay . " 00:00:00"; $end = $aDay . " 23:59:59"; $reports[] = self::getRatingOfDay($pdo,$aDay,$start,$end); } $sql = self::$sql_remarks; $stmt = $pdo->prepare($this->dbutils->resolveTablenamesInSqlString($sql)); $stmt->execute(array($startPeriod,$endPeriod)); $result = $stmt->fetchAll(); return array("statistics" => $reports,"remarks" =>$result); } function getUserSums($pdo) { $sql = "SELECT userid,username as iter,"; $sql .= "ROUND(sum(brutto),2) as sum,"; $sql .= "ROUND(sum(if(paymentid='1',brutto,'0.00')),2) as sumonlybar,"; $sql .= "ROUND(sum(if(status = 'c',brutto,'0.00')),2) as sumcash "; $sql .= "FROM %bill%,%user% WHERE userid=%user%.id AND closingid is null GROUP BY userid,username"; $stmt = $pdo->prepare(DbUtils::substTableAlias($sql)); $stmt->execute(); $result = $stmt->fetchAll(); $sumMax = 0.0; foreach ($result as $a) { if ($a["sum"] > $sumMax) { $sumMax = $a["sum"]; } } return array("max" => $sumMax, "content" => $result); } public static function getOpenTables($pdo) { $sql = "SELECT id,roomname FROM %room% WHERE removed is null"; $rooms = CommonUtils::fetchSqlAll($pdo, $sql,null); $tableCountTotal = 0; $tableCountOpen = 0; $sum = 0.0; foreach($rooms as $aRoom) { $roomId = $aRoom["id"]; $sql = "SELECT count(id) as countid FROM %resttables% WHERE %resttables%.roomid=?"; $howManyTables = CommonUtils::getRowSqlObject($pdo, $sql, array($roomId)); $tableCountTotal += $howManyTables->countid; $sql = "SELECT %resttables%.id as id,%resttables%.tableno as name,IFNULL(SUM(IF(%queue%.toremove='0' AND %queue%.paidtime is null AND %queue%.isclosed is null,%queue%.price,0.00)),0.00) as pricesum FROM %resttables% "; $sql .= " LEFT OUTER JOIN %queue% ON %queue%.tablenr=%resttables%.id WHERE %resttables%.removed is null AND "; $sql .= " %resttables%.roomid=? GROUP BY %resttables%.id,name"; $tables = CommonUtils::fetchSqlAll($pdo, $sql, array($roomId)); foreach($tables as $aTable) { $sum += $aTable["pricesum"]; if ($aTable["pricesum"] != '0.00') { $tableCountOpen++; } } } return array("tablestotal" => $tableCountTotal,"opentables" => $tableCountOpen,"sum" => $sum); } public static function getMaxSoldProductsCount($pdo) { $sql = "SELECT longname,productid,count(productid) as value from %queue%,%bill%,%products% "; $sql .= "WHERE %queue%.productid=%products%.id "; $sql .= "AND productid=%products%.id "; $sql .= "AND billid is not null AND %queue%.billid=%bill%.id "; $sql .= "AND DATE(billdate) = CURDATE() "; $sql .= "AND %bill%.status is null "; $sql .= "GROUP BY longname,productid "; $sql .= "ORDER BY value DESC "; $sql .= "LIMIT 10"; $result = CommonUtils::fetchSqlAll($pdo, $sql, null); return $result; } public static function getMaxSoldProductsSum($pdo) { $sql = "SELECT longname,productid,sum(price) as value from %queue%,%bill%,%products% "; $sql .= "WHERE %queue%.productid=%products%.id "; $sql .= "AND productid=%products%.id "; $sql .= "AND billid is not null AND %queue%.billid=%bill%.id "; $sql .= "AND DATE(billdate) = CURDATE() "; $sql .= "AND %bill%.status is null "; $sql .= "GROUP BY longname,productid "; $sql .= "ORDER BY value DESC "; $sql .= "LIMIT 10"; $result = CommonUtils::fetchSqlAll($pdo, $sql, null); return $result; } public static function getGuestDuration($pdo) { date_default_timezone_set(DbUtils::getTimeZone()); $currentHour = date('H'); $stat = array(); $sql = "SELECT HOUR(paidtime) as hour,ROUND(AVG(TIME_TO_SEC(TIMEDIFF(paidtime,ordertime))/60)) as average"; $sql .= " FROM %queue% WHERE paidtime is not null AND %queue%.toremove='0' AND DATE(paidtime) = DATE(NOW()) AND HOUR(paidtime)=? GROUP BY hour"; $stmt = $pdo->prepare(DbUtils::substTableAlias($sql)); for ($hour = 0; $hour <= $currentHour; $hour++) { $stmt->execute(array($hour)); $result = $stmt->fetchAll(); if (count($result) > 0) { $stat[] = array("hour" => $hour,"average" => $result[0]["average"]); } else { $stat[] = array("hour" => $hour,"average" => 0); } } return $stat; } }